#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
Комментариев нет:
Отправить комментарий