IEnumerable<Task<Request>> requestTasks = CreateRequestTasks();
Task<Trace> traceTask = CreateTraceTask();
var tasks = new List<Task>();
tasks.AddRange(requestTasks);
tasks.Add(traceTask);
await Task.WhenAll(tasks);
How do I get the result from the requestTasks collection?
How do I get the result from the requestTasks collection?
Keep it as a separate (reified) collection:
List<Task<Request>> requestTasks = CreateRequestTasks().ToList();
...
await Task.WhenAll(tasks);
var results = await Task.WhenAll(requestTasks);
Note that the second await Task.WhenAll won't actually do any "asynchronous waiting", because all those tasks are already completed.
Since you have to await them all, you can simply write
IEnumerable<Task<Request>> requestTasks = CreateRequestTasks();
Task<Trace> traceTask = CreateTraceTask();
var tasks = await Task.WhenAll(requestTasks);
var trace = await traceTask;
inside an equivalent async block: it may look clearer imho.
Notice also that the above traceTask starts on create (actually this is the same answer since the question itself is a duplicate).
Related
What is the correct way to handle a part of code that you want to execute at the same time in C#? Each of these calls takes about 3 seconds each (we are making indexing improvements in our systems currently). How do I make these statements execute in parallel with results?
var properties = await _propertyService.GetPropertiesAsync("Fairfax, VA");
var ratings = await _ratingsService.GetRatingsAsync(12549);
You can remove await from invocation and await for result of Task.WhenAll:
var propertiesTask = _propertyService.GetPropertiesAsync("Fairfax, VA");
var ratingsTask = _ratingsService.GetRatingsAsync(12549);
await Task.WhenAll(propertiesTask, ratingsTask);
var properties = propertiesTask.Result;
var ratings = ratingsTask.Result;
Or split method invocation and awaiting (which is usually less preferable option):
var propertiesTask = _propertyService.GetPropertiesAsync("Fairfax, VA");
var ratingsTask = _ratingsService.GetRatingsAsync(12549);
var properties = await propertiesTask;
var ratings = await ratingsTask;
You can use Task.WhenAll for that.
Task.WhenAll will not block and can be awaited, yielding control back to the caller until all tasks finish (in contrast to Task.WaitAll)
In terms of exceptions, If any of the prvided tasks completes in a faulted state, then the returned task will also complete in a Faulted state, where its exceptions will contain the aggregation of the set of the unwrapped exceptions from each of the supplied tasks.
var task1 = _propertyService.GetPropertiesAsync("Fairfax, VA");
var task2 = _ratingsService.GetRatingsAsync(12549);
await Task.WhenAll(task1, task2);
I fire up some async tasks in parallel like the following example:
var BooksTask = _client.GetBooks(clientId);
var ExtrasTask = _client.GetBooksExtras(clientId);
var InvoicesTask = _client.GetBooksInvoice(clientId);
var ReceiptsTask = _client.GetBooksRecceipts(clientId);
await Task.WhenAll(
BooksTask,
ExtrasTask,
InvoicesTask,
ReceiptsTask
);
model.Books = BooksTask.Result;
model.Extras = ExtrasTask.Result;
model.Invoices = InvoicesTask.Result;
model.Receipts = ReceiptsTask.Result;
This results in a lot of typing. I searched the .Net Framework for a way to shorten this up. I imagine it to be lile this. I call the class Collector as I don't know how to name the concept.
var collector = new Collector();
collector.Bind(_client.GetBooks(clientId), out model.Books);
collector.Bind(_client.GetBooksExtras(clientId), out model.Extras);
collector.Bind(_client.GetBooksInvoice(clientId), out model.Invoices);
collector.Bind(_client.GetBooksRecceipts(clientId), out model.Receipts);
collector.Run();
Is this a valid approach? Is there something like that?
Personally, I prefer the code in the question (but using await instead of Result for code maintainability reasons). As noted in andyb952's answer, the Task.WhenAll is not required. I do prefer it for readability reasons; it makes the semantics explicit and IMO makes the code easier to read.
I searched the .Net Framework for a way to shorten this up.
There isn't anything built-in, nor (to my knowledge) any libraries for this. I've thought about writing one using tuples. For your code, it would look like this:
public static class TaskHelpers
{
public static async Task<(T1, T2, T3, T4)> WhenAll<T1, T2, T3, T4>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4)
{
await Task.WhenAll(task1, task2, task3, task4).ConfigureAwait(false);
return (await task1, await task2, await task3, await task4);
}
}
With this helper in place, your original code simplifies to:
(model.Books, model.Extras, model.Invoices, model.Receipts) = await TaskHelpers.WhenAll(
_client.GetBooks(clientId),
_client.GetBooksExtras(clientId),
_client.GetBooksInvoice(clientId),
_client.GetBooksRecceipts(clientId)
);
But is it really more readable? So far, I have not been convinced enough to make this into a library.
In this case I believe that the WhenAll is kind of irrelevant as you are using the results immediately after. Changing to this will have the same effect.
var BooksTask = _client.GetBooks(clientId);
var ExtrasTask = _client.GetBooksExtras(clientId);
var InvoicesTask = _client.GetBooksInvoice(clientId);
var ReceiptsTask = _client.GetBooksRecceipts(clientId);
model.Books = await BooksTask;
model.Extras = await ExtrasTask;
model.Invoices = await InvoicesTask;
model.Receipts = await ReceiptsTask;
The awaits will take care of ensuring you don't move past the 4 later assignments until the tasks are all completed
As pointed out in andyb952's answer, in this case it's not really needed to call Task.WhenAll since all the tasks are hot and running.
But, there are situations where you may still desire to have an AsyncCollector type.
TL;DR:
Async helper function usage example
async Task Async(Func<Task> asyncDelegate) =>
await asyncDelegate().ConfigureAwait(false);
AsyncCollector implementation, usage example
var collector = new AsyncCollector();
collector.Register(async () => model.Books = await _client.GetBooks(clientId));
collector.Register(async () => model.Extras = await _client.GetBooksExtras(clientId));
collector.Register(async () => model.Invoices = await _client.GetBooksInvoice(clientId));
collector.Register(async () => model.Receipts = await _client.GetBooksReceipts(clientId));
await collector.WhenAll();
If you're worried about closures, see the note at the end.
Let's see why someone would want that.
This is the solution that runs the tasks concurrently:
var task1 = _client.GetFooAsync();
var task2 = _client.GetBarAsync();
// Both tasks are running.
var v1 = await task1;
var v2 = await task2;
// It doesn't matter if task2 completed before task1:
// at this point both tasks completed and they ran concurrently.
The problem
What about when you don't know how many tasks you'll use?
In this scenario, you can't define the task variables at compile time.
Storing the tasks in a collection, alone, won't solve the problem, since the result of each task was meant to be assigned to a specific variable!
var tasks = new List<Task<string>>();
foreach (var translation in translations)
{
var translationTask = _client.TranslateAsync(translation.Eng);
tasks.Add(translationTask);
}
await Task.WhenAll(tasks);
// Now there are N completed tasks, each with a value that
// should be associated to the translation instance that
// was used to generate the async operation.
Solutions
A workaround would be to assign the values based on the index of the task, which of course only works if the tasks were created (and stored) in the same order of the items:
await Task.WhenAll(tasks);
for (int i = 0; i < tasks.Count; i++)
translations[i].Value = await tasks[i];
A more appropriate solution would be to use Linq and generate a Task that identifies two operations: the fetch of the data and the assignment to its receiver
List<Task> translationTasks = translations
.Select(async t => t.Value = await _client.TranslateAsync(t.Eng))
// Enumerating the result of the Select forces the tasks to be created.
.ToList();
await Task.WhenAll(translationTasks);
// Now all the translations have been fetched and assigned to the right property.
This looks ok, until you need to execute the same pattern on another list, or another single value, then you start to have many List<Task> and Task inside your function that you need to manage:
var translationTasks = translations
.Select(async t => t.Value = await _client.TranslateAsync(t.Eng))
.ToList();
var fooTasks = foos
.Select(async f => f.Value = await _client.GetFooAsync(f.Id))
.ToList();
var bar = ...;
var barTask = _client.GetBarAsync(bar.Id);
// Now all tasks are running concurrently, some are also assigning the value
// to the right property, but now the "await" part is a bit more cumbersome.
bar.Value = await barTask;
await Task.WhenAll(translationTasks);
await Task.WhenAll(fooTasks);
A cleaner solution (imho)
In this situations, I like to use a helper function that wraps an async operation (any kind of operation), very similar to how the tasks are created with Select above:
async Task Async(Func<Task> asyncDelegate) =>
await asyncDelegate().ConfigureAwait(false);
Using this function in the previous scenario results in this code:
var tasks = new List<Task>();
foreach (var t in translations)
{
// The fetch of the value and its assignment are wrapped by the Task.
var fetchAndAssignTask = Async(async t =>
{
t.Value = await _client.TranslateAsync(t.Eng);
});
tasks.Add(fetchAndAssignTask);
}
foreach (var f in foos)
// Short syntax
tasks.Add(Async(async f => f.Value = await _client.GetFooAsync(f.Id)));
// It works even without enumerables!
var bar = ...;
tasks.Add(Async(async () => bar.Value = await _client.GetBarAsync(bar.Id)));
await Task.WhenAll(tasks);
// Now all the values have been fetched and assigned to their receiver.
Here you can find a full example of using this helper function, which without the comments becomes:
var tasks = new List<Task>();
foreach (var t in translations)
tasks.Add(Async(async t => t.Value = await _client.TranslateAsync(t.Eng)));
foreach (var f in foos)
tasks.Add(Async(async f => f.Value = await _client.GetFooAsync(f.Id)));
tasks.Add(Async(async () => bar.Value = await _client.GetBarAsync(bar.Id)));
await Task.WhenAll(tasks);
The AsyncCollector type
This technique can be easily wrapped inside a "Collector" type:
class AsyncCollector
{
private readonly List<Task> _tasks = new List<Task>();
public void Register(Func<Task> asyncDelegate) => _tasks.Add(asyncDelegate());
public Task WhenAll() => Task.WhenAll(_tasks);
}
Here a full implementation and here an usage example.
Note: as pointed out in the comments, there are risks involved when using closures and enumerators, but from C# 5 onwards the use of foreach is safe because closures will close over a fresh copy of the variable each time.
It you still would like to use this type with a previous version of C# and need the safety during closure, the Register method can be changed in order to accept a subject that will be used inside the delegate, avoiding closures.
public void Register<TSubject>(TSubject subject, Func<TSubject, Task> asyncDelegate)
{
var task = asyncDelegate(subject);
_tasks.Add(task);
}
The code then becomes:
var collector = new AsyncCollector();
foreach (var translation in translations)
// Register translation as a subject, and use it inside the delegate as "t".
collector.Register(translation,
async t => t.Value = await _client.TranslateAsync(t.Eng));
foreach (var foo in foos)
collector.Register(foo, async f.Value = await _client.GetFooAsync(f.Id));
collector.Register(bar, async b => b.Value = await _client.GetBarAsync(bar.Id));
await collector.WhenAll();
I have 2 awaits that I run to get data from an external service:
aaa= await Gateway.GetMyAAA();
bbb= await Gateway.GetBBBB();
I want both to run at the same time and then when both are done, to continue.
How do I Wait for them all ?
var results = await Task.WhenAll(task1, task2);
results is the array of your results and
results[0] is the result of your task1
Don't use await until you get the reference to all the tasks. Then await them all at once.
Task aaa = Gateway.GetMyAAA();
Task bbb = Gateway.GetBBBB();
await Task.WhenAll(aaa, bbb);
'all tasks are complete at this time. now we get the results
var aaaResult = await aaa;
var bbbResult = await bbb;
First, you need to save the Task instances, rather than awaiting them directly:
Task aaaTask = Gateway.GetMyAAA(), bbbTask = Gateway.GetMyBBBB();
Then you wait both (all) of them in a single call to WhenAll():
await Task.WhenAll(aaaTask, bbbTask);
Finally, you retrieve the results:
aaa = await aaaTask;
bbb = await bbbTask;
Note that the final await statements will complete synchronously. The await statement mainly is there so that the compiler will automatically unpack any exceptions that might have occurred and cause them to be thrown "normally", instead of in an aggregated exception.
I am trying to asynchronously complete four tasks and when they are all complete, append them to an object and return it.
Here is my code:
Task[] tasks = new Task[4];
tasks[0] = wtData.GetHFServiceData(wtTransfreeeId);
tasks[1] = wtData.GetTLServicesData(wtTransfreeeId);
tasks[2] = wtData.GetHMAServiceData(wtTransfreeeId);
tasks[3] = wtData.GetHSServiceData(wtTransfreeeId);
Task.WaitAll(tasks);
The problem is, since Task[] has no Result method, I have to define a type like Task<MyType>[]. But, each of the four tasks above return a different type.
How can I wait until all tasks are complete before adding them to my combined object and returning it?
You have to store them as Task<T> before you put them into an array.
Task<YourType1> task1 = wtData.GetHFServiceData(wtTransfreeeId);
Task<YourType2> task2 = wtData.GetTLServicesData(wtTransfreeeId);
...
Task[] tasks = new Task[]{task1, task2, ...};
Task.WaitAll(tasks);
var result1 = task1.Result;//Access the individual task's Result here
...
Avoid blocking wait, consider using Task.WhenAll with await if you're in .Net 4.5. otherwise Task.Factory.ContinueWhenAll is another option.
Using the async/await model, I have a method which makes 3 different calls to a web service and then returns the union of the results.
var result1 = await myService.GetData(source1);
var result2 = await myService.GetData(source2);
var result3 = await myService.GetData(source3);
allResults = Union(result1, result2, result3);
Using typical await, these 3 calls will execute synchronously wrt each other. How would I go about letting them execute concurrently and join the results as they complete?
How would I go about letting them execute in parallel and join the results as they complete?
The simplest approach is just to create all the tasks and then await them:
var task1 = myService.GetData(source1);
var task2 = myService.GetData(source2);
var task3 = myService.GetData(source3);
// Now everything's started, we can await them
var result1 = await task1;
var result1 = await task2;
var result1 = await task3;
You might also consider Task.WhenAll. You need to consider the possibility that more than one task will fail... with the above code you wouldn't observe the failure of task3 for example, if task2 fails - because your async method will propagate the exception from task2 before you await task3.
I'm not suggesting a particular strategy here, because it will depend on your exact scenario. You may only care about success/failure and logging one cause of failure, in which case the above code is fine. Otherwise, you could potentially attach continuations to the original tasks to log all exceptions, for example.
You could use the Parallel class:
Parallel.Invoke(
() => result1 = myService.GetData(source1),
() => result2 = myService.GetData(source2),
() => result3 = myService.GetData(source3)
);
For more information visit: http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel(v=vs.110).aspx
As a more generic solution you can use the api I wrote below, it also allows you to define a real time throttling mechanism of max number of concurrent async requests.
The inputEnumerable will be the enumerable of your source and asyncProcessor is your async delegate (myservice.GetData in your example).
If the asyncProcessor - myservice.GetData - returns void or just a Task without any type, then you can simply update the api to reflect that. (just replace all Task<> references to Task)
public static async Task<TOut[]> ForEachAsync<TIn, TOut>(
IEnumerable<TIn> inputEnumerable,
Func<TIn, Task<TOut>> asyncProcessor,
int? maxDegreeOfParallelism = null)
{
IEnumerable<Task<TOut>> tasks;
if (maxDegreeOfParallelism != null)
{
SemaphoreSlim throttler = new SemaphoreSlim(maxDegreeOfParallelism.Value, maxDegreeOfParallelism.Value);
tasks = inputEnumerable.Select(
async input =>
{
await throttler.WaitAsync();
try
{
return await asyncProcessor(input).ConfigureAwait(false);
}
finally
{
throttler.Release();
}
});
}
else
{
tasks = inputEnumerable.Select(asyncProcessor);
}
await Task.WhenAll(tasks);
}