一个接一个地运行任务序列

Tim*_*son 7 .net c# asynchronous c#-4.0

我有一系列任务,每个任务取决于前一个任务的输出.我想将它表示为单个Task对象,其结果是序列末尾的输出.(如果任务不依赖于彼此,那么我可以并行执行,我会使用TaskFactory.ContinueWhenAll.)

我希望能够实现这个方法:

static Task<TState> AggregateAsync<T, TState>(
    IEnumerable<T> items,
    TState initial,
    Func<TState, T, Task<TState>> makeTask);
Run Code Online (Sandbox Code Playgroud)

我怎样才能有效地依次运行任务呢?我正在使用C#4.0,所以我无法使用async/ await为我做这件事.

编辑:我可以AggregateAsync像这样写:

static Task<TState> AggregateAsync<T, TState>(IEnumerable<T> items, TState initial, Func<TState, T, Task<TState>> makeTask)
{
    var initialTask = Task.Factory.StartNew(() => initial);
    return items.Aggregate(
        initialTask,
        (prevTask, item) =>
            {
                prevTask.Wait(); // synchronous blocking here?
                return makeTask(prevTask.Result, item);
            });
}
Run Code Online (Sandbox Code Playgroud)

但是我肯定会得到一批任务,每个任务同步等待前面的那个任务?

Ste*_*ary 9

简单的方法(使用Microsoft.Bcl.Async):

static async Task<TState> AggregateAsync<T, TState>(
    this IEnumerable<T> items,
    TState initial,
    Func<TState, T, Task<TState>> makeTask)
{
  var state = initial;
  foreach (var item in items)
    state = await makeTask(state, item);
  return state;
}
Run Code Online (Sandbox Code Playgroud)

困难的方式:

static Task<TState> AggregateAsync<T, TState>(
    this IEnumerable<T> items,
    TState initial,
    Func<TState, T, Task<TState>> makeTask)
{
  var tcs = new TaskCompletionSource<TState>();
  tcs.SetResult(initial);
  Task<TState> ret = tcs.Task;
  foreach (var item in items)
  {
    var localItem = item;
    ret = ret.ContinueWith(t => makeTask(t.Result, localItem)).Unwrap();
  }
  return ret;
}
Run Code Online (Sandbox Code Playgroud)

请注意,错误处理在"硬"方式下更加尴尬; AggregateException每个连续项目将包含第一个项目的异常."简单"的方式不会包含这样的异常.