简体   繁体   English

在LINQ语句中使用async / await时实际发生了什么?

[英]What actually happens when using async/await inside a LINQ statement?

The following snippet compiles, but I'd expect it to await the task result instead of giving me a List<Task<T>> . 以下片段编译,但我希望它等待任务结果,而不是给我一个List<Task<T>>

var foo = bars.Select(async bar => await Baz(bar)).ToList()

As pointed out here , you need to use Task.WhenAll : 正如这里指出的,你需要使用Task.WhenAll

var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList();
await Task.WhenAll(tasks);

But a comment points out that the async and await inside the Select() is not needed: 但是评论指出不需要在Select()内部进行asyncawait

var tasks = foos.Select(foo => DoSomethingAsync(foo)).ToList();

A similar question here where someone tries to use an async method inside a Where() . 这里有一个类似的问题,有人试图在Where()使用异步方法。

So async and await inside a LINQ statement is legal syntax, but does it do nothing at all or does it have a certain use? 因此,在LINQ语句中asyncawait是合法的语法,但是它什么都不做或者是否有某种用途?

I recommend that you not think of this as "using async within LINQ". 我建议您不要将其视为“在LINQ中使用async ”。 Keep in mind what's in-between the two: delegates. 请记住两者之间的内容:代表。 Several LINQ operators take delegates, and async can be used to create an asynchronous delegate. 几个LINQ运算符接受委托, async可用于创建异步委托。

So, when you have an asynchronous method BazAsync that returns a Task : 所以,当你有一个返回Task的异步方法BazAsync

Task BazAsync(TBar bar);

then this code results in a sequence of tasks: 那么这段代码会产生一系列任务:

IEnumerable<Task> tasks = bars.Select(bar => BazAsync(bar));

Similarly, if you use async and await within the delegate, you're creating an asynchronous delegate that returns a Task : 同样,如果在委托中使用asyncawait ,则创建一个返回Task的异步委托:

IEnumerable<Task> tasks = bars.Select(async bar => await BazAsync(bar));

These two LINQ expressions are functionally equivalent. 这两个LINQ表达式在功能上是等效的。 There are no important differences. 没有重要的区别。

Just like regular LINQ expressions, the IEnumerable<Task> is lazy-evaluated. 就像常规的LINQ表达式一样, IEnumerable<Task>是惰性求值的。 Only, with asynchronous methods like BazAsync , you usually do not want accidental double-evaluation or anything like that. 只是,与异步方法,如BazAsync ,你通常希望意外双重评价或类似的东西。 So, when you project to a sequence of tasks, it's usually a good idea to immediately reify the sequence. 因此,当您投射到一系列任务时,立即重新确定序列通常是个好主意。 This calls BazAsync for all the elements in the source sequence, starting all the tasks going: 这为源序列中的所有元素调用BazAsync ,开始执行所有任务:

Task[] tasks = bars.Select(bar => BazAsync(bar)).ToArray();

Of course, all we've done with Select is start an asynchronous operation for each element. 当然,我们用Select做的就是为每个元素启动一个异步操作。 If you want to wait for them all to complete, then use Task.WhenAll : 如果你想等待它们全部完成,那么使用Task.WhenAll

await Task.WhenAll(tasks);

Most other LINQ operators do not work as cleanly with asynchronous delegates. 大多数其他LINQ运算符不能与异步委托一起干净地工作。 Select is pretty straightforward: you're just starting an asynchronous operation for each element. Select非常简单:您只是为每个元素启动异步操作。

does it have a certain use 它有一定的用途吗?

Sure. 当然。 With async and await inside a LINQ statement you can eg do something like this: 使用async和await在LINQ语句中,您可以执行以下操作:

var tasks = foos.Select( async foo =>
    {
        var intermediate =  await DoSomethingAsync( foo );
        return await DoSomethingElseAsync( intermediate );
    } ).ToList();
await Task.WhenAll(tasks);

Without async/await inside a LINQ statement you're not awaiting anything inside the LINQ statement, so you can't process the result, or await for something else. 如果没有在LINQ语句中进行异步/等待,那么您不会在LINQ语句中等待任何内容,因此您无法处理结果或等待其他内容。

Without async/await, in the LINQ statement you're only starting tasks, but not waiting for them to complete. 没有async / await,在LINQ语句中,您只是启动任务,而不是等待它们完成。 They'll still complete eventually, but it'll happen long after the control will leave the LINQ statement, so you can only access their results after the WhenAll line will complete, but not inside the LINQ statement. 它们最终仍将完成,但是在控件离开LINQ语句之后很久就会发生,所以你只能在WhenAll行完成之后访问它们的结果,但不能在LINQ语句中访问它们。

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

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