Страницы

Поиск по вопросам

суббота, 11 января 2020 г.

Многопоточность и параллельность при запуске внешнего EXE несколько раз

#c_sharp #многопоточность #инспекция_кода #распараллеливание


Добрый день, уважаемое сообщество. 

Прошу провести code review и дать совет. Есть программа.
Ей надо запустить один и тот же внешний EXE файл N раз с разными входными параметрами.
Дождаться окончания выполнения всех запущенных процессов и собрать результаты в единый,
допустим, массив.

Как использовать параллелизм  и асинхронность (если последняя тут нужна) с максимальной
эффективностью? 

Я пока сделала такое решение:

List> processignDataList = ... //список кортежей
с входными данными
Task[] stackTasks = new Task[processignDataList.Count]; // массив всех тасков
List> tasksResults = new List>(); //список
кортежей с результатами отработки тасков
int i = 0; // счетчик, нужен только для указания элемента массива

foreach (Tuple pair in processignDataList) {
  stackTasks[i] = Task.Factory.StartNew(() => tasksResults.Add(Tuple.Create(pair.Item1,
pairProcessing(cSettings, pair))));
  i++; 
}
Task.WaitAll(stackTasks);


Метод string pairProcessing():


берет свойства из специального объекта cSettings, входные параметры
из pair, 
запускает EXE как Process - process.Start(); 
там же находится ограничение от бесконечного зависания - process.WaitForExit(3000)
потом проверка, что process.Close();
анализ StandardOutput, и на его основе 
формирование некой строки и ее возврат как результата работы метода pairProcessing


Достигаю ли я с таким решением запуска нескольких экземпляров EXE и параллельного
их выполнения? Нужны ли какие-то дополнительные пометки методу pairProcessing(), есть
к нему какие-то требования или он может быть любым? Знаете ли вы решения лучше? (а
решение лучше есть всегда...) Есть ли косяки? 
Спасибо.
    


Ответы

Ответ 1



Во-первых, у вас нет синхронизации доступа к tasksResults - тут может быть неприятная гонка. Во-вторых, если процессов будет много - у вас могут закончиться потоки в пуле, что нежелательно ограничит параллелизм. Впрочем, слишком много процессов все равно не смогут работать параллельно. Первая проблема решается довольно просто - вместо записи в список внутри задачи надо позволить задаче вернуть значение: List>> stackTasks = new List>>(); foreach (Tuple pair in processignDataList) { stackTasks.Add(Task.Factory.StartNew(() => Tuple.Create(pair.Item1, pairProcessing(cSettings, pair)))); } Tuple[] tasksResults = Task.WhenAll(stackTasks).Result; Также можно воспользоваться linq: Tuple[] tasksResults = Task.WhenAll( from pair in processignDataList select Tuple.Create(pair.Item1, pairProcessing(cSettings, pair))) ).Result; или так: Tuple[] tasksResults = Task.WhenAll( processignDataList.Select(pair => Tuple.Create(pair.Item1, pairProcessing(cSettings, pair)))) ).Result; Для решения второй проблемы надо переходить от задач к потокам. Или увеличить размер пула потоков при помощи ThreadPool.SetMaxThreads и ThreadPool.SetMinThreads

Комментариев нет:

Отправить комментарий