是parallel.foreach是提高执行此代码速度的最佳方法

时间:2016-08-18 19:56:22

标签: c# multithreading optimization

我需要重写代码以提高执行原始代码的速度:

数据类:

public class Data
{
    public string Id {get;set;}
    ... Other properties 
}

服务:(例如,有两个以上的jus给你2个)

public class SomeService1
{
    public Result Process(Data data)
    {
        //Load data from different services hire 
    }
}

public class SomeService2
{
    public Result Process(Data data)
    {
        //Load data from different services hire 
    }
}

实际方法

public void Calculate (List<Data> datas)
{
    Result result;
    SomeService1 someService1 = new SomeService1();
    SomeService2 someService2 = new SomeService2();
    // In this place list of data have about 2000 elements 
    foreach(var data in datas)
    {
        switch(data.Id)
        {
            case 1:
                result = someService1.Process(data)
                break;
            case 2:
                result = someService2.Process(data)
                break;
            default:
                result = null;
        }
    ProcesAndSaveDataToDatabase(result);
    }
}

方法Calculate我将List作为此列表中每个元素的参数,它从外部服务中获取数据(服务由Data类中的id确定)。然后它处理这些数据并保存到数据库。对于2000个元素,整个操作大约需要8分钟。 70%的时间是从外部服务收集数据。我必须改变那个时间。我只有一个想法可以做到这一点,但说实话,我无法用数据进行测试,因为只有数据在生产环境上(生产测试是个坏主意)。我有一个想法。如果我朝着正确的方向前进,你能看到它并给我建议吗?

数据类:

public class Data
{
    public string Id {get;set;}
    ... Other properties 
}

服务:(例如,有两个以上的jus给你2个)

public class SomeService1 : IService
{
    public Result Process(Data data)
    {
        //Load data from different services hire 
    }
}

public class SomeService2 : IService
{
    public Result Process(Data data)
    {
        //Load data from different services hire 
    }
}

IService:

public interface IService
{
    Result Process(Data data);
}

实际方法:

Public void Calculate (List<Data> datas)
{
    var split= from data in datas group data by data.Id into newDatas select newDatas
    // Different list split by Id
    Parallel.Foreach(split, new ParallelOptions{MaxDegreeOfParallelism = 4}, datas => 
    {
        Result result;
        IService service = GetService(datas.FirsOfDefault().Id);
        if(service == null) return;
        foreach(var data in datas)
        {
            result = service.Process(data)
            ProcesAndSaveDataToDatabase(result);
        }
    }); 
}

private IService GetService(string id)
{
      IService service = null;
      if(id == null ) return service;
      switch(id)
      {
           case 1:
                service = new SomeService1();
                break;
           case 2: 
                service = new SomeService2();
                break;
      }
      return service;
 }

在这个想法中,我尝试将不同的服务数据拆分为不同的线程。所以在列表中我们将有20个项目Id = 1和10个项目Id = 2它应该创建2个独立的线程并离散处理它应该允许我切断执行时间。这是好方法吗?是否有其他可能性来改进此代码?

谢谢

2 个答案:

答案 0 :(得分:3)

并行ForEach有助于改进CPU绑定任务,但您在上面提到的是并行调用IO绑定的服务。每当你进行IO绑定工作(比如调用外部服务)时,最好使用async并等待而不是并行foreach。

并行ForEach将启动多个线程并阻止这些线程直到工作完成(大约8分钟,所有线程都被阻止)。

Async和Await将在服务调用之间编织工作线程,并有效地使用IO完成端口回调到您的应用程序。这可以避免阻塞多个线程,并允许您更有效地使用计算机的资源。

有关如何在此处进行并行异步调用的更多信息:

https://msdn.microsoft.com/en-us/library/mt674880.aspx

答案 1 :(得分:2)

虽然您将在应用程序中获得使用Parallelism(Parallel.ForEach)的好处,但这并不是提高代码执行速度的唯一方法。

此外,由于您在应用程序中使用LINQ并且可能也在广泛使用它,因此您可能希望尽可能使用 PLINQ (并行LINQ)。

我还建议您尝试分析代码,以确定应用中的热点瓶颈,这可能是让您更好地了解在何处以及如何改善绩效。

另外,正如Patrick所提到的,您应尽可能尝试使用 async 等待

从MSDN查看此文章,我们将为您提供更多见解https://msdn.microsoft.com/en-us/library/ff963552.aspx