Я использую Intel TBB parallel_for для ускорения цикла for, выполняя некоторые вычисления:
tbb::parallel_for(tbb::blocked_range<int>(0,ListSize,1000),Calc);
Calc является объектом класса doCalc
class DoCalc
{
vector<string>FileList;
public:
void operator()(const tbb::blocked_range<int>& range) const{
for(int i=range.begin(); i!=range.end();++i){
//Do some calculations
}
}
DoCalc(vector<string> ilist):FileList(ilist){}
};
Требуется ок. 60 секунд, когда я использую стандартную последовательную форму для цикла и ок. 20 секунд, когда я использую Parallel_for из TBB, чтобы сделать работу. При использовании стандартной нагрузки загрузка каждого ядра моего процессора i5 составляет прибл. 15% (по словам диспетчера задач Windows) и очень неоднородно и ок. 50% и очень однородно при использовании parallel_for.
Интересно, возможно ли получить еще большую нагрузку на ядро при использовании parallel_for. Есть ли другие параметры, кроме grain_size? Как я могу повысить скорость параллельного_для без изменения операций внутри цикла for (здесь как // Выполните некоторые вычисления в примере кода выше).
Как уже предлагал @Eugene Roader, вы можете использовать auto_partitioner (по умолчанию для TBB версии 2.2) для автоматического разбиения диапазона:
tbb::parallel_for(tbb::blocked_range<int>(0,ListSize),Calc,tbb:auto_partitioner());
Я предполагаю, что ваш i5-CPU имеет 4 ядра, поэтому вы получаете ускорение 3 (60 с => 20 с), что уже «довольно неплохо», поскольку при распараллеливании могут быть определенные издержки. Одной из проблем может быть максимальный предел пропускной способности памяти вашего ЦП, который насыщен 3-мя потоками, или у вас может быть много выделений / освобождений в пределах вашей емкости, которые / должны быть синхронизированы между потоками со стандартным диспетчером памяти. Одним из способов решения этой проблемы без значительных изменений кода во внутреннем цикле может быть использование локального распределителя потоков, например для FileList:
vector<string,tbb:scalable_allocator<string>> FileList;
Обратите внимание, что вы должны попробовать tbb :: scalable_allocator для всех других контейнеров, используемых в цикле, чтобы приблизить ускорение распараллеливания к количеству ядер, 4.
Параметр размера зерна является необязательным. Если grainsizee не указан, в шаблон алгоритма должен быть включен разделитель. Разделитель — это объект, который управляет разбиением диапазона. Auto_partitioner предоставляет альтернативу, которая эвристически выбирает размер зерна, так что вам не нужно указывать его. Эвристическая попытка ограничить накладные расходы, при этом предоставляя широкие возможности для балансировки нагрузки.
Перейдите на веб-сайт tbb для получения дополнительной информации. www.threadingbuildingblocks.org
Ответ на ваш вопрос также зависит от соотношения между обращениями к памяти и вычислениями в вашем алгоритме. Если вы выполняете очень мало операций с большим количеством данных, ваша проблема связана с памятью, и это ограничит загрузку ядра. Если, с другой стороны, вы много вычисляете с небольшими данными, ваши шансы на улучшение лучше.