异步等待在LINQ选择 [英] Async await in linq select

查看:57
本文介绍了异步等待在LINQ选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要修改一个现有程序,它包含以下代码:

I need to modify an existing program and it contains following code:

var inputs = events.Select(async ev => await ProcessEventAsync(ev))
                   .Select(t => t.Result)
                   .Where(i => i != null)
                   .ToList();

但这对我来说似乎很奇怪,首先在select中使用asyncawait.根据Stephen Cleary的此答案,我应该可以删除那些答案.

But this seems very weird to me, first of all the use of async and awaitin the select. According to this answer by Stephen Cleary I should be able to drop those.

然后选择第二个Select来选择结果.难道这并不意味着任务根本不异步,而是同步执行(不费吹灰之力就完成了),还是将任务异步执行,并在其余查询完成后执行?

Then the second Select which selects the result. Doesn't this mean the task isn't async at all and is performed synchronously (so much effort for nothing), or will the task be performed asynchronously and when it's done the rest of the query is executed?

我应该根据 Stephen Cleary的另一个答案编写如下代码:

Should I write the above code like following according to another answer by Stephen Cleary:

var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)));
var inputs = tasks.Where(result => result != null).ToList();

和这样完全一样吗?

var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))))
                                       .Where(result => result != null).ToList();

在我从事这个项目的同时,我想更改第一个代码示例,但是我不太热衷于更改(似乎在工作)异步代码.也许我只是担心什么,所有3个代码示例都做完全相同的事情?

While i'm working on this project I'd like to change the first code sample but I'm not too keen on changing (apparantly working) async code. Maybe I'm just worrying for nothing and all 3 code samples do exactly the same thing?

ProcessEventsAsync看起来像这样:

ProcessEventsAsync looks like this:

async Task<InputResult> ProcessEventAsync(InputEvent ev) {...}

推荐答案

var inputs = events.Select(async ev => await ProcessEventAsync(ev))
                   .Select(t => t.Result)
                   .Where(i => i != null)
                   .ToList();

但这对我来说似乎很奇怪,首先在select中使用async和wait.根据Stephen Cleary的回答,我应该可以删除这些内容.

But this seems very weird to me, first of all the use of async and await in the select. According to this answer by Stephen Cleary I should be able to drop those.

Select的调用有效.这两行基本上是相同的:

The call to Select is valid. These two lines are essentially identical:

events.Select(async ev => await ProcessEventAsync(ev))
events.Select(ev => ProcessEventAsync(ev))

(关于从ProcessEventAsync引发同步异常的方式有微小的区别,但是在此代码的上下文中,这根本没有关系.)

(There's a minor difference regarding how a synchronous exception would be thrown from ProcessEventAsync, but in the context of this code it doesn't matter at all.)

然后选择第二个Select(选择).难道这并不意味着任务根本不异步,而是同步执行(不费吹灰之力就完成了),还是将任务异步执行,并在其余查询完成后执行?

Then the second Select which selects the result. Doesn't this mean the task isn't async at all and is performed synchronously (so much effort for nothing), or will the task be performed asynchronously and when it's done the rest of the query is executed?

这意味着查询正在阻止.因此,它并不是真正的异步.

It means that the query is blocking. So it is not really asynchronous.

打破现状:

var inputs = events.Select(async ev => await ProcessEventAsync(ev))

将首先为每个事件启动一个异步操作.然后这行:

will first start an asynchronous operation for each event. Then this line:

                   .Select(t => t.Result)

将一次等待这些操作完成(首先等待第一个事件的操作,然后等待下一个事件,然后等待下一个事件,等等).

will wait for those operations to complete one at a time (first it waits for the first event's operation, then the next, then the next, etc).

这是我不关心的部分,因为它会阻塞并且还会将任何异常包装在AggregateException中.

This is the part I don't care for, because it blocks and also would wrap any exceptions in AggregateException.

和这样完全一样吗?

and is it completely the same like this?

var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)));
var inputs = tasks.Where(result => result != null).ToList();

var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))))
                                       .Where(result => result != null).ToList();

是的,这两个例子是等效的.它们都开始所有异步操作(events.Select(...)),然后异步等待所有操作以任何顺序完成(await Task.WhenAll(...)),然后继续其余工作(Where...).

Yes, those two examples are equivalent. They both start all asynchronous operations (events.Select(...)), then asynchronously wait for all the operations to complete in any order (await Task.WhenAll(...)), then proceed with the rest of the work (Where...).

这两个示例均与原始代码不同.原始代码被阻止,并且会将异常包装在AggregateException中.

Both of these examples are different from the original code. The original code is blocking and will wrap exceptions in AggregateException.

这篇关于异步等待在LINQ选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆