Как запустить все TBB continue_nodes, у которых нет зависимостей

С помощью TBB вы можете создать хороший DAG задач, и он может автоматически запускать их параллельно. Пример из документации:

typedef continue_node< continue_msg > node_t;
typedef const continue_msg & msg_t;

int main() {
  tbb::flow::graph g;
  node_t A(g, [](msg_t){ a(); } );
  node_t B(g, [](msg_t){ b(); } );
  node_t C(g, [](msg_t){ c(); } );
  node_t D(g, [](msg_t){ d(); } );
  node_t E(g, [](msg_t){ e(); } );
  node_t F(g, [](msg_t){ f(); } );
  make_edge(A, B);
  make_edge(B, C);
  make_edge(B, D);
  make_edge(A, E);
  make_edge(E, D);
  make_edge(E, F);
  A.try_put( continue_msg() );
  g.wait_for_all();
  return 0;
}

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

int main() {
  tbb::flow::graph g;

  // Imagine a function did this but in a generic way:      
  node_t A(g, [](msg_t){ a(); } );
  node_t B(g, [](msg_t){ b(); } );
  node_t C(g, [](msg_t){ c(); } );
  node_t D(g, [](msg_t){ d(); } );
  node_t E(g, [](msg_t){ e(); } );
  node_t F(g, [](msg_t){ f(); } );
  make_edge(A, B);
  make_edge(B, C);
  make_edge(D, E);

  // Now how do I now do this?
  A.try_put( continue_msg() );
  D.try_put( continue_msg() );
  F.try_put( continue_msg() );

  g.wait_for_all();
  return 0;
}

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

(Очевидно, я могу вручную подсчитать количество зависимостей для каждой задачи, но я спрашиваю, делает ли это уже TBB.)

Обновлено: чтобы прояснить, я спрашиваю, есть ли функция, при которой автоматически запускает все корневые узлы. Очевидно, я могу сделать это вручную - это то, что делает пример выше!

Нет проблем с несколькими «корневыми узлами», поскольку все они равны, и задача создается и запускается для каждого вызова try_put, даже если g.wait_for_all еще не был выполнен. Объект graph обрабатывает ссылки для всех узлов. Итак, когда все узлы обработаны и в графе нет работы, wait_for_all() служит точкой синхронизации и вернется. Вы даже можете создавать новые ребра во время обработки графа.

Nikita Ponomarev 14.12.2018 19:02

Да, я знаю. Мой вопрос не в том, «как я могу запустить несколько корневых узлов», а в том, «есть ли функция, позволяющая автоматически находить все корневые узлы и запускать их».

Timmmm 15.12.2018 18:49

Тогда, к сожалению, в Flow Graph нет такой встроенной функциональности.

Nikita Ponomarev 17.12.2018 10:49
Стоит ли изучать 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
3
188
1

Ответы 1

Вероятно, это недоразумение по поводу самого flow::graph. Вы должны указать зависимости программно, добавив дуги между узлами. Вы try_put к первому узлу графа, чтобы запустить его. Это единственный способ начать график.

Если у вас есть внешние события, которые вы хотите запустить для графика, вы должны создать слушателя этого события, который try_puts запускает график.

Вы можете создать multifunction_node, который никогда не возвращается, который вы можете использовать для поиска событий и отправки сообщений, но это плохой дизайн TBB. Вы бы навсегда заблокировали задачу TBB для этого multifunction_node, нет-нет. И вам еще нужно что-то try_put к multifunction_node, чтобы он запустился.

Я думаю, вы неправильно поняли мой вопрос. Мне нужна функция, которая автоматически находит A, D и F и запускает их.

Timmmm 15.12.2018 18:48

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