C# Parallel.ForEach和async wait

C# Parallel.ForEach和async wait,c#,async-await,task-parallel-library,parallel.foreach,C#,Async Await,Task Parallel Library,Parallel.foreach,我有这样的方法: public async Task<MyResult> GetResult() { MyResult result = new MyResult(); foreach(var method in Methods) { string json = await Process(method); result.Prop1 = PopulateProp1(json); result.Prop2 =

我有这样的方法:

public async Task<MyResult> GetResult()
{
    MyResult result = new MyResult();

    foreach(var method in Methods)
    {
        string json = await Process(method);

        result.Prop1 = PopulateProp1(json);
        result.Prop2 = PopulateProp2(json);

    }

    return result;
}
但现在我有一个错误:

异步模块或处理程序在异步操作仍挂起时完成


啊,好的。我想我知道现在发生了什么
async method=>
一个“async void”,即“激发并忘记”(不建议用于事件处理程序以外的任何对象)。这意味着调用方无法知道何时完成。。。因此,
GetResult
在操作仍在运行时返回。虽然我的第一个答案的技术细节不正确,但这里的结果是相同的:GetResult返回时,
ForEach
启动的操作仍在运行。您真正能做的唯一一件事就是不要等待
进程
(这样lambda就不再是
异步的
),而是等待
进程
完成每个迭代。但是,这将使用至少一个线程池线程来完成这项任务,因此会对线程池造成轻微的压力——很可能使用
ForEach
是毫无意义的。我不会简单地使用Parallel.ForEach…

async
ForEach
不兼容。特别是,您的
async
lambda正在转换为
async void
方法。有很多(正如我在MSDN文章中所描述的);其中之一是,您无法轻松检测
async
lambda何时完成。ASP.NET将看到您的代码返回,而不完成
async void
方法,并(适当地)抛出异常

您可能希望同时处理数据,而不是并行处理。在ASP.NET上几乎不应该使用并行代码。下面是异步并发处理的代码:

public async Task<MyResult> GetResult()
{
  MyResult result = new MyResult();

  var tasks = Methods.Select(method => ProcessAsync(method)).ToArray();
  string[] json = await Task.WhenAll(tasks);

  result.Prop1 = PopulateProp1(json[0]);
  ...

  return result;
}
public异步任务GetResult()
{
MyResult=新的MyResult();
var tasks=Methods.Select(method=>ProcessAsync(method)).ToArray();
string[]json=wait Task.WhenAll(任务);
result.Prop1=PopulateProp1(json[0]);
...
返回结果;
}
或者,使用,您可以执行以下操作:

using System.Collections.Async;

public async Task<MyResult> GetResult()
{
    MyResult result = new MyResult();

    await Methods.ParallelForEachAsync(async method =>
    {
        string json = await Process(method);    

        result.Prop1 = PopulateProp1(json);
        result.Prop2 = PopulateProp2(json);
    }, maxDegreeOfParallelism: 10);

    return result;
}
使用System.Collections.Async;
公共异步任务GetResult()
{
MyResult=新的MyResult();
等待方法。ParallelForEachAsync(异步方法=>
{
string json=等待进程(方法);
result.Prop1=PopulateProp1(json);
result.Prop2=PopulateProp2(json);
},最大平行度:10);
返回结果;
}

其中,
ParallelForEachAsync
是一种扩展方法。

从哪里得到这个错误?我假设这是一个异常,它是否发生在
GetResult
中?您的
模型是否实际上是一个视图模型,并且它实现了INotifyPropertyChanged并绑定到视图?不,它不是一个视图模型,可能我必须更改名称。它只是一个简单的
,在返回
返回结果时有一些支持异常为什么不在ASP.NET中使用prallel的可能重复?@DirkBoer:并行代码将显著降低ASP.NET的可伸缩性,并干扰其线程池启发式。只有当您有可并行化的CPU绑定工作要做,并且确信您将只有少量并发用户时,它才有用。我得到了与OP完全相同的异常,尽管在使用Parallel时单个用户的响应似乎略有改善,但我可以看到它是如何工作的(Parallel.ForEach)在实时应用程序中可能会意外地影响我们如果我有大量的项目要处理,这段代码是否会尝试同时启动所有项目,需要数百个线程?我认为,将多线程的级别限制在CPU内核的数量上会比同时执行所有操作更快,从而导致巨大的任务切换开销。@ygoe:“这段代码是否会同时启动所有线程”是的。“需要数百个线程?”。
using System.Collections.Async;

public async Task<MyResult> GetResult()
{
    MyResult result = new MyResult();

    await Methods.ParallelForEachAsync(async method =>
    {
        string json = await Process(method);    

        result.Prop1 = PopulateProp1(json);
        result.Prop2 = PopulateProp2(json);
    }, maxDegreeOfParallelism: 10);

    return result;
}