简体   繁体   English

是否可以从异步源以异步方法返回异步项列表?

[英]Is it possible to return a list of async items in an async method from an async source?

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. 我试图从对象列表开始,遍历该列表,对每个对象进行async调用,并以一种可await方式返回结果集,以便消费者可以选择何时await它。 GetMyThings itself uses await before generating the list, so it needs to be async itself and is something like: GetMyThings本身在生成列表之前会使用await ,因此它本身必须是async ,类似于:

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. 基本思想是,我有一些await行,然后使用这些行的结果来生成列表,并且生成每个项目还需要async调用。 I'm trying to avoid blocking within the method (eg .Result ) and instead pass that responsibility/opportunity back to the caller. 我试图避免在方法内阻塞(例如.Result ),而是将这种责任/机会传递回调用者。 Basically, start the tasks in the list but not await them. 基本上,启动列表中的任务,但不await它们。 This naturally makes me want to return Task<List<Thing>> or 'List>`. 这自然使我想返回Task<List<Thing>>或'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. 我最接近的是return Task.WhenAll(things)但是没有用(必须是Task<Task<Thing[]>>await await GetMyThings() 。或者, return Select(...)返回a Task<List<Task<Thing>>>并且需要await Task.WhenAll(await GetMyThings())在使用方。

In both cases one needs double await statements to realize the list. 在这两种情况下,都需要双重await语句来实现该列表。 I'm thinking it's impossible but is there a way to avoid the double await ? 我认为这是不可能的,但是有没有办法避免双重await呢?

Use Task.WhenAll to await all task at once. 使用Task.WhenAll一次等待所有任务。 This way you will run each GetAsync approximately at the same time. 这样,您将大约同时运行每个GetAsync So : 因此:

  1. Start all task 开始所有任务
  2. Await all 等待所有
  3. Return task's results 返回任务的结果

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM