C# AsParallel()或异步/等待
让我们假设执行一个方法C# AsParallel()或异步/等待,c#,.net,asynchronous,task-parallel-library,async-await,C#,.net,Asynchronous,Task Parallel Library,Async Await,让我们假设执行一个方法CountString,给定一个字符串数组和一个int,返回长度大于该int的字符串数。 如果我必须尽可能地利用多核硬件,那么这样做是否足够: public int CountString(string[] s, int i) { return s.AsParallel().Count( res => res.length > i); } 或者我必须使用某种方式的任务,甚至混合任务和PLinq 这只是一个简单的例子,我知道这种方法对硬件性能影响不大 我想
CountString
,给定一个字符串数组和一个int,返回长度大于该int的字符串数。
如果我必须尽可能地利用多核硬件,那么这样做是否足够:
public int CountString(string[] s, int i)
{
return s.AsParallel().Count( res => res.length > i);
}
或者我必须使用某种方式的任务,甚至混合任务和PLinq
这只是一个简单的例子,我知道这种方法对硬件性能影响不大
我想知道这样做是否更好,使用aspallel()
,或者在方法体中声明方法async
并使用wait
(即使我不知道如何做)。编辑:
我看到你的实际问题有点误导,我会尝试回答有意的问题。特别是在这里,使用AsParallel
将是一个很好的方法,因为实际上您不需要等待任何东西。由于您正在处理一个集合,PLINQ或Paralle.ForEach是一个不错的选择。当你有自然的异步I/O绑定操作时,考虑使用<代码>异步等待> /代码>。建议不要这样做
如果您实际测试代码,您甚至可能会惊讶地发现,并行这段代码实际上会对方法执行产生负面的性能代价,这取决于您迭代的数组的大小
很多时候,人们忘记了使用线程实际上是有开销的,即使在线程池外使用线程也是如此。您必须进行最少的CPU密集型工作,这样才值得承受并行化带来的性能损失
如果数组足够长,那么使用AsParallel
就足够了。没有理由添加任务
,因为PLINQ可以很好地处理视差
好的,让我们实际测试一下这段代码。我将迭代一个填充了guid的字符串[]
。代码如下:
主要方法:
void Main()
{
//JIT
Test(0);
Test(100);
Test(1000);
Test(10000);
Test(1000000);
Test(10000000);
}
public void Test(int itemAmount)
{
string[] strings = Enumerable.Range(0, itemAmount).Select(i => Guid.NewGuid()
.ToString()).ToArray();
var stopWatch = Stopwatch.StartNew();
CountStringInParallel(strings, itemAmount);
stopWatch.Stop();
Console.WriteLine("Parallel Call: String amount: {0}, Time: {1}",
itemAmount, stopWatch.Elapsed);
stopWatch.Restart();
CountStringSync(strings, itemAmount);
stopWatch.Stop();
Console.WriteLine("Synchronous Call: String amount: {0}, Time: {1}",
itemAmount, stopWatch.Elapsed);
}
并行和同步:
public int CountStringInParallel(string[] s, int i)
{
return s.AsParallel().Count( res => res.Length > i);
}
public int CountStringSync(string[] s, int i)
{
return s.Count(res => res.Length > i);
}
结果:
并行呼叫:字符串金额:100,时间:00:00:00.0000197
同步呼叫:字符串金额:100,时间:00:00:00.0000026
并行呼叫:字符串金额:1000,时间:00:00:00.0000266
同步呼叫:字符串金额:1000,时间:00:00:00.0000201
并行呼叫:字符串金额:10000,时间:00:00:00.0002060
同步呼叫:字符串金额:10000,时间:00:00:00.0002003
并行呼叫:字符串金额:1000000,时间:00:00:00.0080492
同步呼叫:字符串金额:1000000,时间:00:00:00.0135279
并行呼叫:字符串金额:10000000,时间:00:00:00.0744104
同步呼叫:字符串金额:10000000,时间:00:00:00.1402474
您可以看到多达10000个字符串,同步方法实际上比并行方法更快。只要您不使用异步等待
AsParallel
。没有理由直接使用任务,因为aspallel
会在幕后为您完成任务
重要的是要记住,并行性有一个开销,在您的情况下,这个开销可能会大于并行性的附加值。为了使并行性真正提高性能,您应该处理许多项,并且工作本身应该是非常重要的
但是,如果需要,则需要使用async wait
AsParallel
(以及PLinq的其余部分),因为它早于抽头。您需要使用Task.Run
来并行处理和Task.whalll
towait
。与此类似:
var tasks = items.Select(item => Task.Run(() => Process(item));
var results = await Task.WhenAll(tasks);
// process results
如果你没有非阻塞操作(也没有UI线程),你就不需要任务
。请注意,你的工作太琐碎,无法从并行化中获益。是的,我知道,这只是一个纯粹的示例,必须主要考虑大量字符串来检查。。。顺便说一句,我要读那篇文章,谢谢!当然,这取决于s
的长度。即使对于如此琐碎的工作负载,并行化也会带来好处,这肯定是一个临界点。为什么您认为OP的代码会有负面性能(假设s
array很大而不是很小)?@YuvalItzchakov会有什么不同的解决方案?你能具体点吗;因为我想不起来one@YuvalItzchakov我猜你忽略了OP的密码。OP检查字符串数组中每个字符串的Length
属性,而不是集合的计数。如果数组恰好很大,没有比OP所做的更好的方法了。@Sanci这取决于具体情况。当您在管道或生产者-消费者模式中进行处理时,查看TPL数据流会很有帮助。当您进行IO绑定操作时,async wait
。当你有收藏时,你可以选择感觉更好的,你可以选择PLINQ
或Parallel.ForEach
。我的问题可能写得不好。我想问的是,将该方法声明为async并在方法中使用(我不知道如何使用)“await”是否更好,还是像我那样使用AsParallel()@Sanci,只要其中没有真正的异步(通常是I/O),那么使用async await就没有意义。