改变Parallel.ForEach以更好地接近

时间:2013-12-25 05:13:36

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

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

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

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

代码段:

/* 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
             }
          }
      }
 }

1 个答案:

答案 0 :(得分:3)

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

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