如何在返回集合的 lambda 中使用异步
Posted
技术标签:
【中文标题】如何在返回集合的 lambda 中使用异步【英文标题】:How to use async within a lambda which returns a collection 【发布时间】:2015-07-01 12:14:09 【问题描述】:我有一个异步“上游”方法。我正在尝试遵循最佳实践,并在堆栈中全力以赴。
在 MVC 中的控制器操作中,如果我依赖 .Result(),我可以预见会遇到死锁问题。
将控制器操作更改为异步似乎是可行的方法,但问题是异步方法在 lambda 中被多次调用。
如何等待返回多个结果的 lamda ?
public async Task<JsonResult> GetLotsOfStuff()
IEnumerable<ThingDetail> things= previouslyInitialisedCollection
.Select(async q => await GetDetailAboutTheThing(q.Id)));
return Json(result, JsonRequestBehavior.AllowGet);
你可以看到我已经尝试使 lambda 异步,但这只是给出了一个编译器异常:
无法转换源类型
System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task<ThingDetail>
到目标类型System.Collections.Generic.IEnumerable<ThingDetail>
我哪里错了?
【问题讨论】:
现在您选择返回带有任务的枚举,但是您尝试将其分配给带有 ThingDetail 的枚举,因为您可以使用var
关键字直接声明类型,例如:var things=...
而不是 IEnumerable<ThingDetail> things = ...
result
未在代码块中定义。大概,你的意思是return Json(things, JsonRequestBehavior.AllowGet)
?
【参考方案1】:
将您的Thing
s 集合转换为Task<Thing>
s 的集合。
然后使用Task.WhenAll
加入所有这些任务并等待它。
等待联合任务会给你一个Thing[]
public async Task<JsonResult> GetLotsOfStuff()
IEnumerable<Task<ThingDetail>> tasks = collection.Select(q => GetDetailAboutTheThing(q.Id));
Task<int[]> jointTask = Task.WhenAll(tasks);
IEnumerable<ThingDetail> things = await jointTask;
return Json(things, JsonRequestBehavior.AllowGet);
或者,简洁地使用类型推断:
public async Task<JsonResult> GetLotsOfStuff()
var tasks = collection.Select(q => GetDetailAboutTheThing(q.Id));
var things = await Task.WhenAll(tasks);
return Json(things, JsonRequestBehavior.AllowGet);
小提琴:https://dotnetfiddle.net/78ApTI
注意:由于GetDetailAboutTheThing
似乎返回Task<Thing>
,因此约定是将Async
附加到其名称 - GetDetailAboutTheThingAsync
。
【讨论】:
“就是这样”。太好了,谢谢。我曾尝试过WhenAll 方法,但显然错过了一个中间步骤。我同意你关于异步方法命名约定的观点,我同意。我会实现这个。 两个代码块的最后一行不应该是return Json(things, JsonRequestBehavior.AllowGet);
吗? result
似乎没有在两个代码块中定义。
@M.Babcock 正确,现在已修复。谢谢以上是关于如何在返回集合的 lambda 中使用异步的主要内容,如果未能解决你的问题,请参考以下文章