【问题标题】:Changing Parallel.ForEach to better approach将 Parallel.ForEach 更改为更好的方法
【发布时间】:2014-01-13 04:34:30
【问题描述】:

我使用任务并行库 (TPL) 和 C# 4.5 在 Windows 服务应用程序中实现此业务逻辑:

  • 从远程 RESTful API 获取 JSON 结果(列表)
  • 对于每个项目,从另一个远程检索详细信息的 JSON 结果 RESTful API
  • 对于每个项目的附加业务对象(1000+),使用 Parallel.ForEach 保存到数据库

目前的问题是:将每个项目保存到数据库(同步 DAL)可能需要很长时间,因此 Parallel.ForEach 1000 个项目需要很长时间,并且 Windows 服务应用程序看起来越来越慢。有没有人有好的想法或更好的方法来获得更好的性能?

代码sn-p:

/* Download a list from RESTful API URL.... */
var task = Task.Factory.StartNew(() => { return DownloadListFromRestAPI(); }, TaskCreationOptions.LongRunning);
task.ContinueWith(i => {
     foreach (var r in i.Result)
      {
          /* For each item, download the item details from RESTful API URL.... */
           var taskSecond = Task.Factory.StartNew(() => { return DownloadItemDetailFromRestAPI(r.id); }, TaskCreationOptions.LongRunning);
           taskSecond.ContinueWith(m => {
               /* For each  item detail, get the related business objects, and start Database operation on each object.... */
                List<Item> relatedItems_1000 = s.GetRelatedObjectsIds(m.Result.id);

              /* parallel.ForEach - 1000 or more items  */
                 Parallel.ForEach<Item>(relatedItems_1000, new ParallelOptions { MaxDegreeOfParallelism = 8 }, d => DBLongProcess(d)); /* The DB operation takes long time */
          });
      }
 });

更新:(DBLongProcess() 的代码和锁(我添加了锁,因为并发线程可能会尝试将同一对象修改为 DB))

 private void DBLongProcess(Item item)
 {
    dbDAL.InsertObjectDB(item));
 }

 public class DBDAL
 {
      private readonly object _lock = new object();

      public void InsertObjectDB(Item item)
      {
          lock (_lock)
          {
             if(!item.hasDetail1()){
                 //insert item.detail1...
             }
              if(!item.hasDetail2()){
                //insert item.detail2
             }
          }
      }
 }

【问题讨论】:

  • DBLongProcess 如何提供线程安全?如果做错了,那很容易成为你迟钝的根源。你能把代码也包括进去吗?
  • @ScottChamberlain,请查看我的更新。谢谢你!
  • 不清楚实际问题是什么。 UI 变慢是因为后台占用了太多资源?
  • @NahumLitvin,问题是性能很差。我没有 UI 和 backgroundworker,它是一个服务应用程序。我的问题是“parallel.foreach 1000 个项目”这一行似乎永远需要......有没有更好的方法来获得更好的性能?
  • 你的服务器线程不安全吗?为什么是锁?

标签: c# performance c#-4.0 parallel-processing task-parallel-library


【解决方案1】:

在您的情况下,使用Parallel.ForEach() 不会加快任何速度,因为InsertObjectDB() 中的lock 会强制所有项目按顺序插入。

您需要做的是想办法使DBDAL 线程安全(可能通过使用它的多个实例)。如果这不可行,那么您将不得不在其他地方寻找性能改进。

【讨论】:

  • 谢谢。如果锁被删除并且 DBDAL 是线程安全的,那么 Parallel.ForEach(1000+ 项)在我的情况下是高性能的最佳方法吗?
  • 这很难说,不知道你的实现细节。
  • 虽然我将此标记为答案,但这并不意味着问题已解决。首先,我将监视/跟踪代码以查看大部分时间都花在了哪里。然后我会尝试解除锁定并使 DAL 线程安全。我将使用更多线程安全的缓存策略,一次将所有数据批量提交到数据库。
猜你喜欢
  • 1970-01-01
  • 2012-01-03
  • 1970-01-01
  • 1970-01-01
  • 2015-11-19
  • 2011-01-14
  • 2019-01-22
  • 1970-01-01
  • 2023-03-04
相关资源
最近更新 更多