AsParallel()或async/await

San*_*nci 3 .net c# asynchronous task-parallel-library async-await

让我们假设一个方法CountString,给定一个字符串数组和一个int,返回长度大于int的字符串数.如果我必须尽可能地利用多核硬件,那就足够了:

public int CountString(string[] s, int i) 
{
  return s.AsParallel().Count( res => res.length > i);
}
Run Code Online (Sandbox Code Playgroud)

或者我必须以某种方式使用任务甚至混合任务和PLinq?

它必须只被视为一个简单的例子,我知道这种方法不会对硬件性能产生太大影响.

我想知道这样做是否更好,使用AsParallel(),或者如果更好地声明方法asyncawait在方法体中使用(即使我不知道如何).

Yuv*_*kov 7

编辑:

正如我看到你的实际问题有点误导,我会尝试回答有意的问题.具体来说,这AsParallel将是一个很好的方法,因为实际上没有你需要的东西await.由于您正在处理集合,PLINQ或Paralle.ForEach是一个不错的选择.async-await当你有自然的异步I/O绑定操作时,请考虑使用.建议不要使用异步包装器包装同步方法.


如果您实际测试了代码,您甚至可能会惊讶地看到,这段代码并行实际上会对您的方法执行产生负面的性能成本,具体取决于您要迭代的数组的大小.

很多时候人们忘记了使用线程实际上有开销,即使在线程池中使用线程时也是如此.您必须拥有最少量的CPU密集型工作才能获得并行化的性能.

如果您的阵列足够长,那么使用AsParallel就足够了.没有理由加入,Task因为PLINQ会很好地处理parallalization.

好吧,让我们实际测试这段代码.我将在一个string[]充满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);
}
Run Code Online (Sandbox Code Playgroud)

并行和同步:

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);
}
Run Code Online (Sandbox Code Playgroud)

结果:

并行呼叫:字符串数量: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

您可以看到最多10,000个字符串,同步方法实际上比并行方法快.

  • 当然这取决于`s`的长度.即使对于这样一个微不足道的工作量,肯定会有一个截止点,超出这个截止点,并行化会带来好处. (2认同)