Essentially I'm trying to be able to do this:
var thingTasks = thingFactory.GetMyThings();
// ...
var things = await thingTasks;
I'm trying to start from a list of objects, iterate through that list making an async
call for each one, and returning the set of results in an await
-able way so the consumer can choose when to await
it. GetMyThings
itself uses await
before generating the list, so it needs to be async
itself and is something like:
public async Task<List<Thing>> GetMyThings() {
var thingMakers = await GetThingMakers();
var things = thingMakers.Select(async thing => await thing.GetAsync());
return things;
}
The basic idea is that I have some await
lines, then after that I use the results of those lines to generate a list and generating each item also requires an async
call. I'm trying to avoid blocking within the method (eg .Result
) and instead pass that responsibility/opportunity back to the caller. Basically, start the tasks in the list but not await
them. This naturally makes me want to return Task<List<Thing>>
or 'List>`.
The closest I got was return Task.WhenAll(things)
but that didn't work (it needed to be Task<Task<Thing[]>>
and await await GetMyThings()
. Alternatively, return Select(...)
returning a Task<List<Task<Thing>>>
and needing a await Task.WhenAll(await GetMyThings())
on the consuming side.
In both cases one needs double await
statements to realize the list. I'm thinking it's impossible but is there a way to avoid the double await
?
Use Task.WhenAll
to await all task at once. This way you will run each GetAsync
approximately at the same time. So :
Like this :
public async Task<List<Thing>> GetMyThings()
{
var thingMakers = await GetThingMakers();
var tasks = thingMakers.Select(thing => thing.GetAsync());
var things = await Task.WhenAll(tasks);
return things.ToList();
}
If you want to make the inner tasks await-able outside, you need to actually return them:
public async Task<List<Task<Thing>>> GetMyThings() {
var thingMakers = await GetThingMakers();
var things = thingMakers.Select(thing => thing.GetAsync());
return things.ToList();
}
You can then use this call like this:
List<Task<Thing>> thingTasks = await GetMyThings();
await Task.WhenAll(thingTasks);
List<Thing> = thingTasks.Select(t => t.Result).ToList();
Or even:
List<Thing> things = await GetMyThings()
.ContinueWith(async r =>
{
await Task.WhenAll(r);
return r.Select(r => r.Result).ToList();
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.