2016-02-06 22 views
5

在他PluralSight當然異步C#5,喬恩斯基特提供了名爲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."); 
    } 
} 

this question,馬丁尼爾提供了一個看似更優雅,使用產量回報

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); 
    } 
} 

是仍有些新來的鑽機實施異步編程的我們,任何人都可以描述可能與馬丁·尼爾的實施出現的具體問題是正確的喬恩斯基特的更復雜的實施

+0

@MickyD:沒錯;但我毫不猶豫地將代碼量翻了近四倍,直到我明白,至少在廣泛的筆觸中,爲什麼。 ** usr **在下面給我提供了兩個很好的理由。 –

+0

同意。我剛剛遇到了「看似更優雅」的問題。在編程的各個方面,不能總是將行數與優雅等同起來。 Servy在下面提出了一些好的觀點。 :) – MickyD

回答

5

第二個解決方案具有二次的時間複雜度的問題得到解決。循環運行N次,每次調用都會爲這些任務添加N個continuations。除非您確定任務的數量非常少,否則請勿使用該代碼。

Remove調用導致二次的時間複雜度爲好。

此外,代碼的第二片被阻擋。你只有在完成任務後才能取回任務。 InCompletionOrder立即爲您提供這些任務,並在稍後完成。

我會認爲InCompletionOrder作爲庫方法。將其放入實用程序文件中,它不會導致您的維護問題。它的行爲將永遠不會改變。這裏我沒有看到代碼大小的問題。

+2

喬恩也正確地處理例外和取消任務,而其他片段基本上只在所有任務成功完成時才起作用。 Honsetly說,而事實上,它的阻止(主要在做的'IEnumerable的返回類型>'基本上是一個謊言)是*遠*比性能問題更重要,所以我會引發與這兩個點,只提性能一個小點。 – Servy

+0

@Servy你確定這個異常行爲嗎?第二個片段不訪問它返回的任務的結果。另一點值得注意。 – usr

相關問題