简体   繁体   English

并行使用

[英]Parallel.ForEach Usage

I've got the following: 我有以下几点:

[HttpPost]
public async Task<IEnumerable<PlotAutocompleteModel>> Get()
{
     IEnumerable<PlotDomain> plots = await plotService.RetrieveAllPlots();
     var concurrent = ConcurrentQueue<PlotAutoCompleteModel>();
     Parallel.ForEach(plots, (plot) =>
     {
          concurrent.Enqueue(new PlotAutocompleteModel(plot);
     });

     return concurrent;
}

With this usage, it takes about two seconds. 使用此方法大约需要两秒钟。 Compared to: return plots.Select(plot => new PlotsAutocompleteModel(plot)).ToList(); 相比: return plots.Select(plot => new PlotsAutocompleteModel(plot)).ToList(); which takes about four and a half seconds. 这大约需要四个半秒。

But I've always been told that for a simple transformation of a domain model into a view model, a Parallel.ForEach isn't ideal, mostly because it should be for more com-putative code. 但是我总是被告知,对于将域模型简单地转换为视图模型而言, Parallel.ForEach并不理想,主要是因为它应该用于更多可计算的代码。 Which my usage clearly doesn't do. 我的用法显然不起作用。

Clarification: Where you would use significantly more resources, for instance you have a bitmap, a large quantity, which you have to rasterize and create new images from. 澄清:您将在这里大量使用更多资源,例如,您有大量位图,必须对其进行栅格化并从中创建新图像。

Is this the proper option for this code? 这是此代码的正确选择吗? I clearly see a performance gain due to the raw amount of records I'm iterating then transforming. 由于要迭代然后转换的原始记录数量,我可以清楚地看到性能的提高。 Does a better approach and exist? 是否存在更好的方法并存在?

Update: 更新:

public class ProductAutocompleteModel
{
     private readonly PlotDomain plot;
     public ProductAutocompleteModel(PlotDomain plot)
     {
          this.plot = plot;
     }

     public string ProductName => plot.Project.Name;
     // Another fourteen exist.
}

With this usage, it takes about two seconds. 使用此方法大约需要两秒钟。 Compared to... about four and a half seconds. 相比...大约四分半秒。

But I've always been told that for a simple transformation of a domain model into a view model, a Parallel.ForEach isn't ideal, mostly because it should be for more com-putative code. 但是我总是被告知,对于将域模型简单地转换为视图模型而言,Parallel.ForEach并不理想,主要是因为它应该用于更多可计算的代码。

Yeah, um... there's no way - absolutely no way - that a "simple transformation of a domain model into a view model" should take four and a half seconds. 是的,嗯...没有办法-绝对没有办法-“将域模型简单转换为视图模型”需要花费四分半秒的时间。 There is something seriously wrong there. 那里有严重的错误。 It should take maybe half a millisecond or so. 大概需要半毫秒左右。 So, your PlotAutocompleteModel constructor is doing something like 10,000 times the amount of work that is normal. 因此,您的PlotAutocompleteModel构造函数执行的工作量是正常工作量的10,000

Is this the proper option for this code? 这是此代码的正确选择吗? I clearly see a performance gain due to the raw amount of records I'm iterating then transforming. 由于要迭代然后转换的原始记录数量,我可以清楚地看到性能的提高。

Probably not, because you're hosting on ASP.NET. 可能不是,因为您托管在ASP.NET上。 If you use parallelism on ASP.NET, you will see individual requests complete faster, but it will negatively impact the scalability of your web server as a whole. 如果在ASP.NET上使用并行性,则将看到单个请求的完成速度更快,但这会对Web服务器整体的可伸缩性产生负面影响。 For this reason, I never recommend parallelism in ASP.NET handlers. 因此,我从不建议在ASP.NET处理程序中使用并行性。 (There are specific situations where it would be acceptable - such as a non-public server where you know you have a hard upper limit on the number of simultaneous users - but as a general rule, it's not a good idea). (在某些特定情况下这是可以接受的,例如,您知道并发用户数量有严格的上限的非公共服务器,但通常来说,这不是一个好主意)。

Since your PlotAutocompleteModel constructor is taking several orders of magnitude longer than expected, I suspect that it's doing blocking I/O as part of its work. 由于您的PlotAutocompleteModel构造函数花费时间比预期的长几个数量级 ,因此我怀疑它在做阻塞I / O的工作。 The best solution here is to change the blocking I/O to asynchronous I/O, and then use concurrent asynchrony, something like this: 最好的解决方案是将阻塞I / O更改为异步I / O,然后使用并发异步,如下所示:

class PlotAutocompleteModel
{
  public static async Task<PlotAutocompleteModel> CreateAsync(PlotDomain plot)
  {
    ... // do asynchronous I/O to create a PlotAutocompleteModel.
  }
}

[HttpPost]
public async Task<IEnumerable<PlotAutocompleteModel>> Get()
{
  IEnumerable<PlotDomain> plots = await plotService.RetrieveAllPlots();
  var tasks = plots.Select(plot => PlotAutocompleteModel.CreateAsync(plot));
  return await Task.WhenAll(tasks);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM