2016-08-18 4 views
0

У меня есть код, который мне нужно переписать, чтобы улучшить скорость выполнения исходного кода:ли Parallel.ForEach это лучший способ улучшить скорость выполнения этого кода

класса данных:

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

Услуги: (Есть более чем 2 я 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 как параметр для каждого элемента в этом списке, он захватывает данные из внешней службы (услуга определяется по идентификатору в классе данных). Затем он обрабатывает эти данные и сохраняет их в базе данных. Для 2000 элементов целая операция занимает около 8 мин. 70% времени собирает данные из внешней службы. Я должен изменить это время. У меня есть только одна идея сделать это, но, честно говоря, я не могу протестировать ее с данными, потому что только данные относятся к производственной среде (а тестирование на производстве - плохая идея). У меня есть одна идея. Можете ли вы посмотреть на это и посоветуете мне, если я пойду в правильном направлении?

класс данных:

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

Услуги: (Есть более чем 2 I Jus дают U 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 разделенных потока и обработать их дискретно, это должно позволить мне отключить время выполнения. Это хороший способ? Есть ли другие возможности для улучшения этого кода?

Благодаря

+0

Если 70% времени тратится вытягивать данные из службы, которые были бы то, что вам нужно оптимизировать. У вас есть контроль над сервисом? – SledgeHammer

+0

Нет. Там за пределами службы, и у меня есть только служебная ссылка на нее – Aht

+0

, поэтому требуется ~ 5.6 минут, чтобы вытащить данные поочередно сейчас? Если вы сделаете эту часть параллельной, она будет быстрее, так как вы нажимаете на эту услугу несколько раз подряд. Кроме того, используйте профилировщик в своем локальном коде, чтобы узнать, что вы можете оптимизировать на своей стороне ... но вы никогда не будете быстрее, чем услуга может доставить. – SledgeHammer

ответ

3

Parallel ForEach помогает улучшить ЦП задачи, но вы упоминаете выше вы вызываете услуги параллельно которому привязано IO. Всякий раз, когда вы выполняете работу с IO (например, вызывается внешняя служба), вам лучше использовать async и ждать, а не параллельно foreach.

Parallel ForEach будет вращать несколько потоков и блокировать эти потоки, пока работа не будет выполнена (около 8 минут со всеми заблокированными потоками).

Async и Await соткают рабочие потоки между служебными вызовами и эффективно используют порты завершения ввода-вывода для возврата в ваше приложение. Это позволяет избежать блокировки нескольких потоков и позволяет более эффективно использовать ресурсы вашего компьютера.

Более подробную информацию о том, как сделать параллельные асинхронные вызовы здесь:

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

+0

Проблема с Async заключается в том, что у меня уже есть метод из сервисов (это не мой), а этот сервис просто вызывает метод из WCF. В этом случае я должен запросить изменения внутри этих служб? Или я могу сделать асинхронный вызов этой услуги? – Aht

+0

svcutil может генерировать методы async с флагом/async. Вам не нужно изменять реализацию службы, это делается в прокси-сервере клиента. «Добавить ссылку на службу» в visual studio имеет флажок для создания асинхронных методов. –

+0

Хорошо, что я использовал методы Async и удалил несколько «foreach» и использовал «Parallel.Foreach», и теперь у меня есть 2 мин 30 с для 3000 элементов вместо 8 минут в 2000 году. Я верю, что это максимум – Aht

2

В то время как вы будете пожинать преимущества использования Параллелизм (Parallel.ForEach) в своем приложении, что это не единственный способ улучшая скорость выполнения кода.

Кроме того, поскольку вы используете LINQ в своем приложении, и вы также можете использовать его широко, вы можете использовать PLINQ (Parallel LINQ), где это возможно.

Я также предлагаю вам попробовать профилирование свой код, чтобы определить горячие точки и узкие места в приложении, которое может дать вам лучшее представление о том понимании, где и как вы можете улучшить производительность.

Кроме того, как уже упоминалось, Патрик, вы должны попробовать использовать асинхр и ждут везде, где это возможно.

Проверьте эту статью из MSDN, что даст вам больше понимания https://msdn.microsoft.com/en-us/library/ff963552.aspx

Смежные вопросы