Параллельные задачи. Запускайте параллельные потоки, но не ждите завершения других задач и получайте последние данные из базы данных

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

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 данных из БД, то для параллельного выполнения задач используется один и тот же источник данных.

Вот чего я хочу достичь -

  1. Я хочу запускать задачи параллельно.
  2. Мне не нужно ждать завершения других задач
  3. Если одна задача выполнена, назначьте ей другую работу (перейдите в базу данных, получите данные и назначьте новую работу).

«Мне не нужно ждать завершения других задач» — это называется «выстрелил и забыл», и в целом это нецелесообразно. Вы уверены, что?

Theodor Zoulias 17.06.2024 14:49

Этот вопрос может быть связан: Task.WhenAny с отменой незавершенных задач и тайм-аутом.

Theodor Zoulias 17.06.2024 14:53

Я понял, что вы имели в виду, но я подумал: мы должны иметь контроль над задачами (а не запустить и забыть), но не нужно ждать других задач в списке, скажем, одна задача занимает очень много времени, тогда Для завершения всех моих тем потребуется больше времени.

Abhijith Nayak 17.06.2024 14:57

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

Abhijith Nayak 17.06.2024 15:05

Если задача выполняется очень долго, это означает, что либо ваше оборудование, либо какое-либо другое подключенное оборудование не может выполнить задачу. Запустив и забыв задачу, вы упрощаете запуск новой длительной операции, пока еще выполняется предыдущая, что еще больше перегружает систему. Не только ваши пользователи, но и администраторы других систем будут ненавидеть ваше программное обеспечение.

Theodor Zoulias 17.06.2024 15:11

Понятно, это занимает много времени, потому что нужно получать данные из нескольких систем (около 5), которые являются приложениями поставщика, поэтому мы ничего не можем там сделать, поэтому я подумал, что вариант заключается в том, чтобы запустить долго работающие приложения в другом списке. задач. Дайте мне знать, если это имеет смысл.

Abhijith Nayak 17.06.2024 15:16

Можете ли вы передать CancellationToken, когда звоните в эти приложения на стороне поставщика? Если нет, уверены ли вы, что эти приложения на стороне поставщика будут рады, если вы вызовете каждое из них одновременно (потому что вы запустили и забыли предыдущие вызовы)?

Theodor Zoulias 17.06.2024 15:23

Можете ли вы объяснить более подробно, что вы подразумеваете под «Если одна задача выполнена, назначьте на эту задачу другую работу»

Magnus 17.06.2024 15:25

Конечно, @Магнус. Скажем, например: Задача 1, Задача 2, Задача 3, Задача 1 выполняется за короткое время (скажем, 1 минута), Задача 2 и Задача 3 могут занять много времени (скажем, 15 минут), поскольку Задача 1 завершена с обработкой, мне нужно идти. в БД и получить ожидающие обработки запросы для назначения задаче 1

Abhijith Nayak 17.06.2024 15:28

Я не вижу, чтобы вы делали это в текущем коде. Можете ли вы добавить это, чтобы я мог понять, что вы имеете в виду.

Magnus 17.06.2024 15:30

Что на самом деле делает DownloadSSR? Если, как следует из названия, выполняет HTTP-вызовы, вам следует использовать ParallelForEachAsync. Загрузка привязана к вводу-выводу. Использование Parallel.ForEach приведет к блокировке всех ядер ЦП во время ожидания ответа от удаленного сервера. Кажется, тебе это очень нужно await Parallel.ForEachAsync(data,(item,ct)=>DownloadSSR(mediator, sourcePath, item,ct));

Panagiotis Kanavos 17.06.2024 15:30

Есть много вопросов о том, как выполнить несколько одновременных HTTP-вызовов, и много хороших ответов, показывающих, как это делать правильно. Вы можете использовать Parallel.ForEachAsync, вы можете использовать блоки Dataflow.

Panagiotis Kanavos 17.06.2024 15:32

@PanagiotisKanavos да, ты прав. Он получит данные из нескольких систем (около 5), создаст отчет и загрузит его. все вызовы между системами - это HTTP-вызовы.

Abhijith Nayak 17.06.2024 15:32

Итак, как только задача DownloadSSR будет выполнена, вы хотите отменить другую текущую задачу и продолжить выполнение этой?

Magnus 17.06.2024 15:33

Пробовали await Parallel.ForEachAsync(data,(item,ct)=>DownloadSSR(mediator, sourcePath, item,ct)); ? ForEachAsync понимает задачи и будет ждать завершения всех ожидающих задач, прежде чем вернуться. По умолчанию он запускает столько одновременных задач, сколько имеется ядер, но вы можете увеличить или уменьшить это количество, если вам нужно. Parallel.ForEach не понимает задачи, поэтому то, что вы написали, эквивалентно вызову метода async void. Этого нельзя ожидать.

Panagiotis Kanavos 17.06.2024 15:35

@Magnus Нет, я не хочу отменять, как я уже сказал выше. Если есть 3 задачи, задача 1 выполняется за короткое время, задача 2 и задача 3 занимают много времени, тогда я не хочу ничего отменять, задача 2 и задача 3 позволяют для ответа требуется время, после завершения задачи 1 я хочу поручить другую работу по загрузке отчета

Abhijith Nayak 17.06.2024 15:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
16
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это позволит выполнять задачи параллельно и выдавать вам результат по мере их выполнения.

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 не предоставят загруженный отчет, поскольку это занимает больше времени?

Abhijith Nayak 17.06.2024 15:46

Я изменил его так, чтобы вы получали задания в порядке их выполнения.

Magnus 17.06.2024 16:30
Ответ принят как подходящий

Спасибо за все ответы.

На самом деле мне нужен механизм «запустил и забыл» для моего требования, и я знаю, что это создаст некоторую нагрузку на мой сервер, но меня это устраивает, поскольку я ограничиваю количество потоков до 3 (используя максимальную степень параллелизма), и я подумал Hangfire — один из лучших для этого требования.

Другие вопросы по теме