Как сделать пул потоков в C++ TBB?
Возможно, я не измеряю это правильно, но у меня есть простой код, с которым я играю. Я не думаю, что это пул потоков, потому что если я делаю рабочий блок очень большим, то процессор увеличивается до 190-199%(у меня двухъядерный), но если я уменьшаю, рабочий блок меньше, но гораздо больше этих блоков, чем мой процессор запускает программу на 140-160%.
Я думаю, что происходит то, что потоки не объединяются в пул, а уничтожаются / создаются при необходимости, что замедляет работу программы, когда рабочие нагрузки меньше. я использую tbb::task_scheduler_init
контролировать количество потоков, но я не знаю, как сказать tbb, чтобы сохранить поток в живых.
Вот некоторый код для иллюстрации проблемы:
#include <iostream>
#include <list>
#include <tbb/task.h>
#include <tbb/task_group.h>
//#include <stdlib.h>
#include "tbb/task_scheduler_init.h"
#include <boost/thread.hpp>
using namespace tbb;
long fib(long a)
{
if (a < 2) return 1;
return fib(a - 1) + fib(a - 2);
}
class PrintTask
{
public:
void operator()()
{
//std::cout << "hi world!: " << boost::this_thread::get_id() << std::endl;
fib(10);
}
};
int main()
{
tbb::task_scheduler_init init(4); //creates 4 threads
task_group group;
for (int i = 0; i < 2000000; ++i)
{
group.run(PrintTask());
//std::cout << i << std::endl;
}
std::cout << "done" << std::endl;
group.wait();
return(0);
}
если вы измените fib на 40-45, работа для каждого потока станет большой, так что она достигнет полной скорости, но если вы используете текущую настройку, то задания очень малы, но многие из них выполняются.
примечание: я заметил, что, возможно, это связано с тем, что в приведенном выше случае он полностью использует мою память (4 гигабайта). Может ли замедление быть связано с этим? Кроме того, почему эта программа занимает всю память? Что хранится в памяти, если я просто вызываю поток, нет ли очереди, указывающей, сколько раз запустить, или он сохраняет весь поток в памяти для запуска?
Извините за странные вопросы, я прочитал учебник, но все еще смущен его поведением (хотя я получаю ожидаемый результат).
Благодарю.
2 ответа
Вы не должны сильно беспокоиться об использовании процессора, а скорее смотрите на время выполнения и ускорение по сравнению с последовательным.
Есть несколько вещей, которые вы должны понимать о tbb:
Вы можете думать о том, что накладные расходы по планированию задачи в основном постоянны (это не совсем, но достаточно близко). Чем меньше объем работы, который вы запланировали, тем ближе подход к этой константе. Если вы приблизитесь к этой константе, вы не увидите ускорений.
Также потоки бездействуют, когда они не могут найти работу. Я предполагаю, что когда вы вызываете 'fib(10)', стоимость вызова run и необходимое распределение задач приближаются к стоимости фактического выполнения работы.
Точнее говоря, если у вас действительно есть 2000000 элементов с одной и той же задачей, вы, вероятно, должны вызывать parallel_for или parallel_for_each.
-Rick
Просто чтобы подчеркнуть последний пункт Рика, документы для task_group
государство:
ПРЕДУПРЕЖДЕНИЕ. Создание большого количества задач для одной группы задач не масштабируется, поскольку создание задач становится узким местом в последовательном процессе. Если вы создаете несколько параллельных задач, попробуйте вместо этого использовать parallel_for (4.4) или parallel_invoke (4.12) или структурировать порождение как рекурсивное дерево.
Я бы на самом деле добавил parallel_do
к этому списку, который, вероятно, применим к вашему варианту использования "не знаю количество задач". Его аргументы включают "фидер", который может добавить больше задач; но еще раз обратите внимание, что комментарии в документах не касаются задач по одному. Выборочная цитата:
Разработайте свой алгоритм так, чтобы тело часто добавляло больше, чем одну работу.... Чтобы добиться ускорения, размер зерна B::operator() должен быть порядка не менее ~100000 тактов. В противном случае внутренние издержки параллельного_для затопляют полезную работу.
Если вы ищете примеры нетривиальных TBB (за parallel_for
учебник и т. д.), руководство по шаблонам TBB очень хорошее.