在他的PluralSight课程异步C# 5中,Jon Skeet提供了一个方便的扩展方法InCOmpletionOrder的实现:
在这个问题中,Martin Neal提供了一种看起来更加优雅的实现方式,使用yield return。
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.");
}
}
在这个问题中,Martin Neal提供了一种看起来更加优雅的实现方式,使用yield return。
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);
}
}
作为对异步编程还有些陌生的人,能否有人描述一下马丁·尼尔(Martin Neal)的实现中可能出现的具体问题,以及乔恩·斯基特(Jon Skeet)更复杂的实现是如何解决这些问题的。