c# - 如何将此 Parallel.ForEach 代码转换为异步/等待

标签 c# asynchronous

我在理解 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/

相关文章:

c# - SqlGeography 空间操作缓慢 - SQL Server 2016

c# - 异步方法可以从同步代码异步运行吗

c# - 在单线程 API 中处理事件处理程序休眠的最佳方法?

java - 如何将 Mono 变成真正的异步(非响应式!)方法调用?

c# - 验证目标数据库架构是否符合 Entity Framework 中的内容?

c# - 将字符数组转换为枚举数组?

c# - 如何以编程方式创建数据 block ?

c# - 从父级在 PictureBox 上画一条线

c# - 如何在 .NET 中测试并发场景?

android - 使用异步 HTTP 请求在 Activity 中触发 onSuccess