运行顺序的任务,一个接一个接一个、顺序、任务

2023-09-03 05:28:09 作者:你说的一辈子只是一阵子

我有一个序列的任务,其中的每一个取决于previous 1的输出。我想重新present这是一个工作对象,其结果是该序列的末端的输出。 (如果任务不依赖于彼此,然后我能做到这一点的同时,我会使用 TaskFactory.ContinueWhenAll

I have a sequence of tasks, where each one depends on the output of the previous one. I'd like to represent this as a single Task object, whose result is the output of the end of the sequence. (If the tasks didn't depend on one another then I could do it in parallel and I would use TaskFactory.ContinueWhenAll.)

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

I'd like to be able to implement this method:

static Task<TState> AggregateAsync<T, TState>(
    IEnumerable<T> items,
    TState initial,
    Func<TState, T, Task<TState>> makeTask);

如何有效地运行的任务一个接一个顺序?我使用C#4.0,所以我不能用异步 / 等待来为我做的。

How can I efficiently run the tasks one after another in sequence? I'm using C# 4.0 so I can't use async/await to do it for me.

编辑:我可以写 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);
            });
}

但可以肯定,我会收到得到一批任务,其中每一个块同步等待一个?

But surely I'll get a batch of tasks, each of which blocks synchronously waiting for the one before it?

推荐答案

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

The easy way (using 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;
}

硬的方式:

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

请注意,错误处理是比较尴尬的硬的方式;从第一个项目的异常将被包装在一个 AggregateException 由每个连续的项目。 易的方法不换行的例外是这样的。

Note that error handling is more awkward with the "hard" way; an exception from the first item will be wrapped in an AggregateException by each successive item. The "easy" way does not wrap exceptions like this.

 
精彩推荐
图片推荐