Я использую библиотеку задач для параллельного запуска нескольких задач и использую приведенный ниже код, чтобы дождаться завершения других задач.
Parallel.ForEach(DatafromDB,
item => { DownloadSSR(mediator, sourcePath, item,stoppingToken).Wait();
});
Используя это, я почувствовал, что на самом деле я не делаю это параллельно, потому что, например, для 3 задач: Task1, Task2 и Task3.
Задача 1 скажем занимает 15 минут, а остальные задачи - 1 минуту соответственно, в этом случае мы ждем завершения всех Заданий.
Чтобы добиться этого, я использую еще одну опцию — «MaxDegreeOfParallelism».
Parallel.ForEach(DatafromDB,
new ParallelOptions { MaxDegreeOfParallelism = 3},
item => { DownloadSSR(mediator, sourcePath, item,stoppingToken).Wait();
});
Теперь задачи выполняются параллельно, но данные из БД берутся только впервые.
Например: если я получил 3 данных из БД, то для параллельного выполнения задач используется один и тот же источник данных.
Вот чего я хочу достичь -
Этот вопрос может быть связан: Task.WhenAny с отменой незавершенных задач и тайм-аутом.
Я понял, что вы имели в виду, но я подумал: мы должны иметь контроль над задачами (а не запустить и забыть), но не нужно ждать других задач в списке, скажем, одна задача занимает очень много времени, тогда Для завершения всех моих тем потребуется больше времени.
Я подумал еще об одном способе: иметь пакет задач, для решения которых потребуется время, и другой пакет для задач, которые не требуют много времени, вам тоже нужно мнение по этому поводу.
Если задача выполняется очень долго, это означает, что либо ваше оборудование, либо какое-либо другое подключенное оборудование не может выполнить задачу. Запустив и забыв задачу, вы упрощаете запуск новой длительной операции, пока еще выполняется предыдущая, что еще больше перегружает систему. Не только ваши пользователи, но и администраторы других систем будут ненавидеть ваше программное обеспечение.
Понятно, это занимает много времени, потому что нужно получать данные из нескольких систем (около 5), которые являются приложениями поставщика, поэтому мы ничего не можем там сделать, поэтому я подумал, что вариант заключается в том, чтобы запустить долго работающие приложения в другом списке. задач. Дайте мне знать, если это имеет смысл.
Можете ли вы передать CancellationToken, когда звоните в эти приложения на стороне поставщика? Если нет, уверены ли вы, что эти приложения на стороне поставщика будут рады, если вы вызовете каждое из них одновременно (потому что вы запустили и забыли предыдущие вызовы)?
Можете ли вы объяснить более подробно, что вы подразумеваете под «Если одна задача выполнена, назначьте на эту задачу другую работу»
Конечно, @Магнус. Скажем, например: Задача 1, Задача 2, Задача 3, Задача 1 выполняется за короткое время (скажем, 1 минута), Задача 2 и Задача 3 могут занять много времени (скажем, 15 минут), поскольку Задача 1 завершена с обработкой, мне нужно идти. в БД и получить ожидающие обработки запросы для назначения задаче 1
Я не вижу, чтобы вы делали это в текущем коде. Можете ли вы добавить это, чтобы я мог понять, что вы имеете в виду.
Что на самом деле делает DownloadSSR? Если, как следует из названия, выполняет HTTP-вызовы, вам следует использовать ParallelForEachAsync. Загрузка привязана к вводу-выводу. Использование Parallel.ForEach приведет к блокировке всех ядер ЦП во время ожидания ответа от удаленного сервера. Кажется, тебе это очень нужно await Parallel.ForEachAsync(data,(item,ct)=>DownloadSSR(mediator, sourcePath, item,ct));
Есть много вопросов о том, как выполнить несколько одновременных HTTP-вызовов, и много хороших ответов, показывающих, как это делать правильно. Вы можете использовать Parallel.ForEachAsync, вы можете использовать блоки Dataflow.
@PanagiotisKanavos да, ты прав. Он получит данные из нескольких систем (около 5), создаст отчет и загрузит его. все вызовы между системами - это HTTP-вызовы.
Итак, как только задача DownloadSSR будет выполнена, вы хотите отменить другую текущую задачу и продолжить выполнение этой?
Пробовали await Parallel.ForEachAsync(data,(item,ct)=>DownloadSSR(mediator, sourcePath, item,ct)); ? ForEachAsync понимает задачи и будет ждать завершения всех ожидающих задач, прежде чем вернуться. По умолчанию он запускает столько одновременных задач, сколько имеется ядер, но вы можете увеличить или уменьшить это количество, если вам нужно. Parallel.ForEach не понимает задачи, поэтому то, что вы написали, эквивалентно вызову метода async void. Этого нельзя ожидать.
@Magnus Нет, я не хочу отменять, как я уже сказал выше. Если есть 3 задачи, задача 1 выполняется за короткое время, задача 2 и задача 3 занимают много времени, тогда я не хочу ничего отменять, задача 2 и задача 3 позволяют для ответа требуется время, после завершения задачи 1 я хочу поручить другую работу по загрузке отчета





Это позволит выполнять задачи параллельно и выдавать вам результат по мере их выполнения.
var tasks = DatafromDB.Select(item => DownloadSSR(mediator, sourcePath, item, stoppingToken)).ToList();
await foreach (var result in ProcessTasksInOrder(tasks))
{
await DoStuff(result);
}
public static async IAsyncEnumerable<T> ProcessTasksInOrder<T>(IEnumerable<Task<T>> tasks)
{
var tasksToProcess = tasks.ToList();
while (tasksToProcess.Count > 0)
{
var completedTask = await Task.WhenAny(tasksToProcess);
yield return completedTask.Result;
tasksToProcess.Remove(completedTask);
}
}
Спасибо @Магнус. Если задача 1 завершена, мне снова нужно вызвать в базу данных и назначить обновленный список «DatafromDB», и, согласно приведенному здесь коду, задача 2 и задача 3 не предоставят загруженный отчет, поскольку это занимает больше времени?
Я изменил его так, чтобы вы получали задания в порядке их выполнения.
Спасибо за все ответы.
На самом деле мне нужен механизм «запустил и забыл» для моего требования, и я знаю, что это создаст некоторую нагрузку на мой сервер, но меня это устраивает, поскольку я ограничиваю количество потоков до 3 (используя максимальную степень параллелизма), и я подумал Hangfire — один из лучших для этого требования.
«Мне не нужно ждать завершения других задач» — это называется «выстрелил и забыл», и в целом это нецелесообразно. Вы уверены, что?