2012-12-16 112 views
2

如果不使用c#異步/等待功能,什麼纔是循環異步操作而不阻塞的最佳方式?如何在沒有異步/等待的情況下循環異步方法

例如,在for循環內異步下載URL列表的HTML。

我繼續在TPL的while循環中繼續調用自己,如果有更多的工作....但是有沒有更好的方法?

+0

有一些情況下使用的IEnumerable的iasync結果像powerthreading(異步伺機正是基於這樣的),你不要有淨4.5支持庫。 – NickD

+0

你爲什麼要避免使用'async'''await'? – svick

+0

我正在尋求避免異步/等待,因爲它的一種新的語言功能(在社區還沒有大量的生產時間),我關心它的副作用 - 內存使用情況,錯誤情況等。我寧願看社區先犯錯,然後繼續。 – Micah

回答

2

您描述的模式並不差,但您可以將它抽象爲輔助方法。類似於ForEachAsyncConvertAllAsync。這可以消除代碼中的循環。這將非必要的複雜性降至最低。


這裏是ForEachAsync實現:

public static Task ForEachAsync<T>(this TaskFactory factory, IEnumerable<T> items, Func<T, int, Task> getProcessItemTask) 
    { 
     TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); 

     IEnumerator<T> enumerator = items.GetEnumerator(); 
     int i = 0; 

     Action<Task> continuationAction = null; 
     continuationAction = ante => 
      { 
       if (ante.IsFaulted) 
        tcs.SetException(ante.Exception); 
       else if (ante.IsCanceled) 
        tcs.TrySetCanceled(); 
       else 
        StartNextForEachIteration(factory, tcs, getProcessItemTask, enumerator, ref i, continuationAction); 
      }; 

     StartNextForEachIteration(factory, tcs, getProcessItemTask, enumerator, ref i, continuationAction); 

     tcs.Task.ContinueWith(_ => enumerator.Dispose(), TaskContinuationOptions.ExecuteSynchronously); 

     return tcs.Task; 
    } 
    static void StartNextForEachIteration<T>(TaskFactory factory, TaskCompletionSource<object> tcs, Func<T, int, Task> getProcessItemTask, IEnumerator<T> enumerator, ref int i, Action<Task> continuationAction) 
    { 
     bool moveNext; 
     try 
     { 
      moveNext = enumerator.MoveNext(); 
     } 
     catch (Exception ex) 
     { 
      tcs.SetException(ex); 
      return; 
     } 

     if (!moveNext) 
     { 
      tcs.SetResult(null); 
      return; 
     } 

     Task iterationTask = null; 
     try 
     { 
      iterationTask = getProcessItemTask(enumerator.Current, i); 
     } 
     catch (Exception ex) 
     { 
      tcs.SetException(ex); 
     } 

     i++; 

     if (iterationTask != null) 
      iterationTask.ContinueWith(continuationAction, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, factory.Scheduler ?? TaskScheduler.Default); 
    } 
+0

這是一個非常有趣的想法。你以前做過嗎? – Micah

+0

是的。我已經添加了我的實現。你可以從這個構建其他的基元(一個異步for-loop將是一個通過Enumerable.Range(0,...)的foreach)。 – usr

+0

現在我將開始研究如何使這個循環並行 - 你做到了嗎? – Micah