2012-12-16 72 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