Всем привет!
Имеется некоторый проект числодробилки, в нем красной линией проложена очередь задач. Любой запрос от клиента обрабатывается в задаче.
На основе этого я хочу распараллелить запрос, чтобы он сам генерировал задачи, по завершении которых возможна дальнейшая обработка и возможно генерация очередной порции задач уже следующего этапа и этих этапов может быть много, пока все не посчитаем и в итоге в асинхронном режиме не выдадим результат клиенту.
Классический вариант с ожиданием завершения моей группы задач не подходит - ожидая завершения потоков я блокирую один из небольшого числа потоков, который можно было бы задействовать для обработки других запросов:
// Этап 1
auto taskGroup = threadPool.createTaskGroup ();
while (conditionToCreateManyJobsIsTrue ()) {
addJob (taskGroup, []() {
//Do some job
});
}
// Тут мы блокируем один из потоков очереди
// Хуже еще то, что если количество запросов от клиентов будет больше или равно количеству потоков в очереди, то при таком решении сервер просто навсегда зависнет
taskGroup.join ();
// Этап 2 аналогичен по структуре распараллеливания этапу 1
...
Если исходить из того, что действия на 2-ом этапе выполняются после завершения последней задачи на этапе 1 приходит идея, чтобы каждая лямбда функция держала объект со счетчиком ссылок, и действия 2-го этапа начались в деструкторе этого объекта.
std::shared_ptr< NextStage > nextStage = sugarWrapperToCreateExceptionGuardedDestructorClass ([]() {
// Действия на 2-ом этапе
});
// Этап 1
auto taskGroup = threadPool.createTaskGroup ();
while (conditionToCreateManyJobsIsTrue ()) {
addJob (taskGroup, [=nextStage]() {
//Do some job
});
}
Теперь код задачи после комментария
// Этап 1
Но мне не нравится, что я определяю 2-ой этап до первого, и поэтому код воспринимается хуже. Если этапов будет еще больше, то определять их нужно в обратном порядке.
У кого-нибудь есть идеи как еще можно решить эту задачу?