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

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

问题描述

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

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

但这对我来说似乎很奇怪,首先在选择中使用 asyncawait .根据 Stephen Cleary 的 this answer,我应该可以放弃这些.

然后是选择结果的第二个 Select.这是否意味着任务根本不是异步的而是同步执行的(付出这么多努力是白费力气),还是会异步执行任务,并在完成后执行查询的其余部分?

我是否应该根据 Stephen Cleary 的另一个回答编写上述代码:

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

和这个完全一样吗?

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

当我在做这个项目时,我想更改第一个代码示例,但我不太热衷于更改(显然正在工作)异步代码.也许我只是无所事事,所有 3 个代码示例都做完全相同的事情?

ProcessEventsAsync 如下所示:

async TaskProcessEventAsync(InputEvent ev) {...}

解决方案

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

<块引用>

但这对我来说似乎很奇怪,首先在选择中使用 async 和 await.根据 Stephen Cleary 的这个回答,我应该可以放弃这些.

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

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

(关于如何从 ProcessEventAsync 抛出同步异常,存在细微差别,但在此代码的上下文中,这根本无关紧要.)

<块引用>

然后是选择结果的第二个 Select.这是否意味着任务根本不是异步的而是同步执行的(付出这么多努力是白费力气),还是会异步执行任务,并在完成后执行查询的其余部分?

这意味着查询正在阻塞.所以它并不是真正的异步.

分解:

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

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

 .Select(t => t.Result)

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

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

<块引用>

和这个完全一样吗?

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

是的,这两个例子是等价的.它们都启动所有异步操作(events.Select(...)),然后异步等待所有操作以任意顺序完成(await Task.WhenAll(...)),然后继续剩下的工作(Where...).

这两个示例都与原始代码不同.原始代码是阻塞的,会将异常包装在 AggregateException 中.

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

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.

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?

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

and is it completely the same like this?

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

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

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.

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

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

(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.)

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.

Breaking it down:

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).

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

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...).

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天全站免登陆