是否有理由更喜欢这些实现中的一个而不是另一个

Pie*_*ens 5 c# asynchronous task-parallel-library

在他的PluralSight课程异步C#5中,Jon Skeet为名为InCOmpletionOrder的便利扩展方法提供了这种实现:

public static IEnumerable<Task<T>> InCompletionOrder<T>(this IEnumerable<Task<T>> source)
{
    var inputs = source.ToList();
    var boxes  = inputs.Select(x => new TaskCompletionSource<T>()).ToList();
    int currentIndex = -1;

    foreach (var task in inputs)
    {
        task.ContinueWith(completed =>
        {
            var nextBox = boxes[Interlocked.Increment(ref currentIndex)];
            PropagateResult(completed, nextBox);
        }, TaskContinuationOptions.ExecuteSynchronously);
    }

    return boxes.Select(box => box.Task);
}

private static void PropagateResult<T>(Task<T> completedTask,
      TaskCompletionSource<T> completionSource)
{
    switch(completedTask.Status)
    {
      case TaskStatus.Canceled:
          completionSource.TrySetCanceled();
          break;
      case TaskStatus.Faulted:
          completionSource.TrySetException(completedTask.Exception.InnerExceptions);
          break;
      case TaskStatus.RanToCompletion:
          completionSource.TrySetResult(completedTask.Result);
          break;
      default:
          throw new ArgumentException ("Task was not completed.");
    }
}
Run Code Online (Sandbox Code Playgroud)

这个问题中,Martin Neal使用收益率回报提供了一个看似更优雅的实现

public static IEnumerable<Task<T>> InCompletionOrder<T>(this IEnumerable<Task<T>> source)
{
    var tasks = source.ToList();

    while (tasks.Any())
    {
        var t = Task.WhenAny(tasks);
        yield return t.Result;
        tasks.Remove(t.Result);
    }
}
Run Code Online (Sandbox Code Playgroud)

对于异步编程的严谨性仍然有点新,任何人都可以描述Martin Neal实现中可能出现的特定问题,这些问题可以通过Jon Skeet更复杂的实现得到妥善解决

usr*_*usr 5

第二种解决方案具有二次时间复杂度问题.循环运行N次,每次WhenAny调用为这些任务添加N个延续.除非您确定任务数量非常少,否则不要使用该代码.

Remove调用也会导致二次时间复杂度.

此外,第二段代码是阻止.您只有在完成任务时才能恢复.InCompletionOrder立即为您提供这些任务,并在以后完成.

我认为InCompletionOrder是一种图书馆方法.将它放入实用程序文件中,它不会导致维护问题.它的行为将/永远不会改变.我不认为代码大小是一个问题.

  • Jon还正确地处理了例外和取消的任务,而另一个片段基本上只在所有任务成功完成时才起作用.值得注意的是,它阻塞的事实(基本上使得"IEnumerable <Task <T >>"的返回类型基本上是一个谎言)比性能问题更重要,所以我带领这两点并且只提到表现作为一个小问题. (2认同)