Использовать асинхронные делегаты или ThreadPool.QueueUserWorkItem для массового параллелизма?
-
08-07-2019 - |
Вопрос
У меня есть .NET-приложение, которое обрабатывает около 300 000 записей при пакетном импорте, и на каждую запись требуется несколько секунд, поэтому я хотел бы распараллелить это.В следующем коде, в чем разница между ProcessWithAnsycDelegates()
и ProcessWithThreadPool()
?
public class ResultNotification
{ public EventHandler event Success;
public EventHandler event Fail;
internal void Notify(bool sucess) {if (success) Success(); else Fail();}
}
public static class Processor
{ public ResultNotification ProcessWithAnsycDelegates(Record record)
{ var r = new ResultNotification();
Func<Record,bool> processRecord=new RecordProcessor().ProcessRecord;
processRecord.BeginInvoke
( record
,ar => result.Notify(processRecord.EndInvoke(ar))
,null);
return r;
}
public ResultNotification ProcessWithThreadPool(Record r)
{ var r = new ResultNotification();
var rp = new RecordProcessor();
ThreadPool.QueueWorkUserItem(_=>result.Notify(rp.ProcessRecord(r)));
return r;
}
}
Решение
В этом случае не так много, так как они оба используют пул потоков под капотом. Я бы сказал, что QueueUserWorkItem () легче читать и видеть, что происходит по сравнению с BeginInvoke.
Эта ссылка может помочь. Это старая информация, но все еще в основном применима http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml р>
Другие советы
Буквальный ответ на вопрос заключается в том, что оба используют threadpool, так что разница невелика, если единственным соображением является производительность.
Если вопрос действительно заключается в получении наилучшей производительности, то может помочь узнать, что при использовании threadpool действительно есть проблемы.К ним относятся:
- Блокировка конфликта в рабочей очереди
- Чрезмерное переключение контекста.Если у вас есть 2 процессора и последовательность рабочих элементов, то 25 потоков на самом деле не помогут.Лучше иметь 2 потока, по одному для каждого процессора
Возможно, стоит изучить TPL и PLINQ:
- Параллельный LINQ, Выполняющий Запросы На многоядерных процессорах
- Оптимизация параллельной производительности управляемого кода Для многоядерных машин
- Улучшена поддержка Параллелизма В Следующей версии Visual Studio
Одним из примеров используемого TPL, который они приводят, является:
for (int i = 0; i < 100; i++) {
a[i] = a[i]*a[i];
}
Для:
Parallel.For(0, 100, delegate(int i) {
a[i] = a[i]*a[i];
});