如何在 c++ TBB 中制作线程池

  • 本文关键字:线程 TBB c++ c++ tbb
  • 更新时间 :
  • 英文 :


我可能没有正确测量这一点,但我有一些简单的代码。我不认为这是一个线程池,因为如果我使工作单元非常大,那么 cpu 就会达到 190-199%(我有双核(,但如果我降低工作单元,但这些单元比我的 CPU 运行程序要多得多 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 场免费演出(。 经济放缓可能与此有关吗?还有为什么这个程序会占用所有内存?它将其存储在内存中是什么,如果我只是调用线程,那么没有队列告诉它运行多少次还是将整个线程保存在内存中以运行?

阅读了教程,但仍然对其行为感到困惑(尽管我确实得到了预期的结果(。

您不应该太担心 CPU 利用率,而应该查看执行时间和加速与顺序。

您需要了解有关 tbb 的几点:

你可以认为调度任务的开销基本上是恒定的(它不完全是,但它足够接近(。 您安排的工作量越小,就越接近此常数。 如果你接近这个常数,你就不会看到加速。

此外,线程在找不到工作时会处于空闲状态。我猜当你调用 'fib(10(' 时,调用 run 的成本和必要的任务分配正在接近实际执行工作的成本。

更具体地说,如果您确实有 2000000 个项目具有相同的任务,您可能应该调用parallel_for或parallel_for_each。

-瑞克

为了强调 Rick 的最后一点,task_group的文档指出:

警告:为单个task_group创建大量任务是 不可扩展,因为任务创建成为串行瓶颈。如果 创建多个并发任务,请考虑使用 改为parallel_for (4.4( 或parallel_invoke (4.12(,或构建 作为递归树生成。

我实际上会parallel_do添加到该列表中,因为它可能适用于您不知道的任务数量的前期用例。 它的参数包括一个可以添加更多任务的"馈线";但再次注意文档中的评论不是一次处理一个任务。 选择性报价:

设计您的算法,使主体经常添加多个算法 刺头。 ... 为了实现加速,B::operator(( 的颗粒化 需要至少 ~100,000 个时钟周期。否则 parallel_do的内部开销淹没了有用的工作。

如果您正在寻找非平凡的 TBB 示例(除了parallel_for和教程等(,TBB 模式手册非常好。

最新更新