C# 如何将此Parallel.ForEach代码转换为async/await

C# 如何将此Parallel.ForEach代码转换为async/await,c#,asynchronous,C#,Asynchronous,我在异步/等待方面遇到了一些问题。我正在帮助使用一个现有的代码库,该代码库包含以下代码(为简洁起见,简化): List buyerContext=GetBuyers(); var results=新列表(); Parallel.ForEach(buyerContext,buyerContext=> { //下面的调用创建到远程web服务器的连接,该远程web服务器 //最多需要15秒才能做出响应 var结果=投标(买方上下文); 如果(结果!=null) 结果。添加(结果); } foreach

我在异步/等待方面遇到了一些问题。我正在帮助使用一个现有的代码库,该代码库包含以下代码(为简洁起见,简化):

List buyerContext=GetBuyers();
var results=新列表();
Parallel.ForEach(buyerContext,buyerContext=>
{
//下面的调用创建到远程web服务器的连接,该远程web服务器
//最多需要15秒才能做出响应
var结果=投标(买方上下文);
如果(结果!=null)
结果。添加(结果);
}
foreach(结果中的var结果)
{
//在这里做一些基于
//Parallel.ForEach已完成其所有调用
}
如何将此代码转换为异步代码而不是使用async/await进行并行处理?我遇到了一些非常严重的性能问题,我认为这是使用并行方法处理多个网络i/O操作的结果

我自己也尝试过几种方法,但我从VisualStudio收到警告,我的代码将同步执行,或者我不能在异步方法之外使用wait关键字,所以我确信我只是缺少一些简单的东西

编辑#1:我也愿意接受异步/等待的替代方案。根据我目前的阅读,这似乎是正确的方法


编辑#2:此应用程序是一项Windows服务。它向几个“买家”发出呼吁要求他们对特定数据段进行投标。在继续处理之前,我需要返回所有投标。

基本上,为了使用
async wait
bid
方法应具有此签名,而不是当前签名:

public async Task<Result> BidAsync(BuyerContext buyerContext);
之后

//Signature
public Task<string> ReceiveStringFromClientAsync();

//Call
string messageFromClient = await ReceiveStringFromClientAsync();
“使事情异步化”的关键是从叶子开始。在这种情况下,从网络代码(未显示)开始,将任何同步调用(例如,
WebClient.DownloadString
)更改为相应的异步调用(例如,
HttpClient.GetStringAsync
),然后等待该调用

使用
await
将强制调用方法为
async
,并将其返回类型从
T
更改为
Task
。此时添加
async
后缀也是一个好主意,这样您就可以遵循了。然后将该方法的所有调用者都更改为使用
await
,这将然后要求它们是
async
,等等。重复此过程,直到有了
bidaync
方法可供使用

然后,您应该考虑替换并行循环;这对于
任务来说非常容易。whalll

List<BuyerContext> buyerContexts = GetBuyers();
var tasks = buyerContexts.Select(buyerContext => BidAsync(buyerContext));
var results = await Task.WhenAll(tasks);

foreach (var result in results)
{
  ...
}
List buyerContext=GetBuyers();
var tasks=buyerContext.Select(buyerContext=>BidAsync(buyerContext));
var结果=等待任务.WhenAll(任务);
foreach(结果中的var结果)
{
...
}

您可以添加出价方法定义吗?如果它与网络相关,那么查看网络代码将非常有帮助:)听起来像是在循环中进行非常昂贵的调用。你需要所有的结果吗?如果用户要求更多,您可能会得到一些结果,然后只返回更多结果吗?请参阅,以获得一个简单的解决方案。Bid方法有大量的逻辑,用于建立网络连接的实际代码隐藏在几个层次的抽象基类中。在我看来,
async
更可能是这里的解决方案
Parallel.ForEach
只是并行调用,网络接口是造成速度减慢的原因。没错,我从单行改为variable+add,但忘记了第二行,正在修复!谢谢一个问题:异步方法是否必须以async()结尾?询问的原因是Bid()方法包含对通过接口实现的方法的调用。如果我必须将方法名称更改为Async(),我必须更新大约50个项目:注意,除非bidasync是真正异步的,否则它将具有与原始版本完全相同的性能。提高性能的最简单方法是增加线程池大小。
//Signature
public Task<string> ReceiveStringFromClientAsync();

//Call
string messageFromClient = await ReceiveStringFromClientAsync();
List<BuyerContext> buyerContexts = GetBuyers();
var results = new List<Result>();

List<Task> tasks = new List<Task>();

//There really is no need for Parallel.ForEach unless you have hundreds of thousands of requests to make.
//If that's the case, I hope you have a good network interface!
foreach (var buyerContext in buyerContexts)
{
    var task = Task.Run(async () =>
    {
        var result = await BidAsync(buyerContext);        

        if (result != null)
            results.Add(result);
    });

    tasks.Add(task);
}

//Block the current thread until all the calls are completed
Task.WaitAll(tasks);

foreach (var result in results)
{
  // do some work here that is predicated on the 
  // Parallel.ForEach having completed all of its calls
}
List<BuyerContext> buyerContexts = GetBuyers();
var tasks = buyerContexts.Select(buyerContext => BidAsync(buyerContext));
var results = await Task.WhenAll(tasks);

foreach (var result in results)
{
  ...
}