我在理解 async/await 时遇到了一些麻烦。我正在帮助一个现有的代码库,该代码库具有以下代码(为简洁起见进行了简化):
List<BuyerContext> buyerContexts = GetBuyers();
var results = new List<Result>();
Parallel.ForEach(buyerContexts, buyerContext =>
{
//The following call creates a connection to a remote web server that
//can take up to 15 seconds to respond
var result = Bid(buyerContext);
if (result != null)
results.Add(result);
}
foreach (var result in results)
{
// do some work here that is predicated on the
// Parallel.ForEach having completed all of its calls
}
如何使用 async/await 将此代码转换为异步代码而不是并行代码?我遇到了一些非常严重的性能问题,我认为这是对多个网络 I/O 操作使用并行方法的结果。
我自己尝试了几种方法,但我从 Visual Studio 收到警告说我的代码将同步执行,或者我不能在异步方法之外使用 await 关键字,所以我确定我只是遗漏了一些东西简单。
编辑 #1: 我也对 async/await 的替代方案持开放态度。根据我目前的阅读,这似乎是正确的方法。
编辑 #2: 此应用程序是 Windows 服务。它召集了几个“买家”,要求他们对特定数据进行投标。在继续处理之前,我需要退回所有出价。
最佳答案
“使事物异步”的关键是从叶子开始。在这种情况下,从您的网络代码(未显示)开始,并将您拥有的任何同步调用(例如 WebClient.DownloadString
)更改为相应的异步调用(例如 HttpClient.GetStringAsync
)。那么await
那个电话。
使用 await
将强制调用方法为 async
,并将其返回类型从 T
更改为至 Task<T>
.此时添加 Async
也是一个好主意。后缀,所以你正在关注 the well-known convention .然后获取所有 that 方法的调用者并将它们更改为使用 await
同样,这将要求它们是 async
, 等等。重复直到你有一个 BidAsync
使用方法。
然后您应该考虑替换您的并行循环;使用 Task.WhenAll
很容易做到这一点:
List<BuyerContext> buyerContexts = GetBuyers();
var tasks = buyerContexts.Select(buyerContext => BidAsync(buyerContext));
var results = await Task.WhenAll(tasks);
foreach (var result in results)
{
...
}
关于c# - 如何将此 Parallel.ForEach 代码转换为异步/等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32899319/