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);
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.
Edit: I could write AggregateAsync
like this:
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?
c# - Run sequence of tasks, one after the other - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.
Concurrent tasks progress at the same time in the worker system but they don't progress simultaneously. Parallel tasks are executed by different workers at the same time. Concurrency refers to how a worker system handles multiple tasks while parallelism refers to how a worker system handles a single task.
WhenAll(IEnumerable<Task>) Creates a task that will complete when all of the Task objects in an enumerable collection have completed.
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;
}
The hard way:
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;
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With