C++ 如何在c++;TBB?

C++ 如何在c++;TBB?,c++,tbb,C++,Tbb,我可能没有正确地衡量这一点,但我有一些简单的代码,我正在玩。我不认为这是线程池,因为如果我使工作单元非常大,那么cpu将变为190-199%(我有双核),但是如果我使工作单元变小,但比我的cpu运行140-160%的程序要多得多 我认为正在发生的事情是,线程没有被池化,而是在需要时被销毁/创建,这使得程序在工作负载较小时速度变慢。我正在使用tbb::task\u scheduler\u init来控制线程的数量,但我不知道如何告诉tbb使线程保持活动状态 下面是一些代码来说明这个问题: #inc

我可能没有正确地衡量这一点,但我有一些简单的代码,我正在玩。我不认为这是线程池,因为如果我使工作单元非常大,那么cpu将变为190-199%(我有双核),但是如果我使工作单元变小,但比我的cpu运行140-160%的程序要多得多

我认为正在发生的事情是,线程没有被池化,而是在需要时被销毁/创建,这使得程序在工作负载较小时速度变慢。我正在使用
tbb::task\u scheduler\u 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);
}
#包括
#包括
#包括
#包括
//#包括
#包括“tbb/task\u scheduler\u init.h”
#包括
使用名称空间tbb;
长fib(长a)
{
如果(a<2)返回1;
返回fib(a-1)+fib(a-2);
}
类打印任务
{
公众:
void运算符()()
{

//std::cout您不应该太担心CPU利用率,而应该看看执行时间和加速比与顺序

关于tbb,您需要了解以下几点:

你可以把安排一项任务的开销看作是基本不变的(虽然不是很高,但已经足够接近了)。你安排的工作量越小,就越接近这个常数。如果你接近这个常数,你就看不到加速

当线程找不到工作时,它们也会空闲。我猜当你调用“fib(10)”时,调用run和必要的任务分配的成本接近实际执行工作的成本

更具体地说,如果您确实有2000000个项目具有相同的任务,那么您可能应该为每个项目调用parallel\u或parallel\u


-Rick

为了强调Rick的最后一点,for
任务组
声明:

警告:为单个任务组创建大量任务是非常困难的 不可扩展,因为任务创建成为串行瓶颈。如果 创建多个并发任务,考虑使用 parallel_for(4.4)或parallel_invoke(4.12),或者 作为递归树生成

实际上,我会将
parallel\u do
添加到该列表中,因为它可能适用于您的未知任务数的前期用例。它的参数包括一个“feeder”,可以添加更多任务;但再次注意,文档中的注释不是一次处理一个任务。选择性引用:

设计算法,使主体通常添加多个 一件作品。 ... 为了实现加速,B::operator()的粒度 至少需要约100000个时钟周期。否则, 并行计算的内部开销确实会淹没有用的工作


如果您正在寻找非平凡TBB的示例(超越
parallel\u for
等),TBB非常好。

我不太确定问题是什么。如果您认为TBB不太可能正在创建/销毁线程,那么请检查线程ID。@Rick ahhh您说得对……那么我可能对线程有更深的误解,因为为什么较小的工作会使线程运行较慢?我没有在线程之间共享任何数据,所以CKK不应该是个问题。我能想到的唯一一件事是线程需要一段时间才能启动(但您的右侧线程id是相同的)当我用线程池和执行器来尝试Java的等价物时。submit
来发送工作,那么它似乎总是以接近190%的速度运行,这取决于你的代码,Java的垃圾收集器在你的应用程序正在完成的任何实际工作的基础上,可以很高兴地使用大约一个CPU来处理。因此,比较Java和C之间的CPU利用率++没有告诉你任何有用的东西。唯一与并行性有关的是,它是否能在经过的挂钟时间内更快地完成你想要的事情。拥有
void操作符()
not
const
将以错误C3848结束:类型为“const PrintTask”的表达式将丢失一些const volatile限定符,以便在MSVC中调用“void PrintTask::operator()(void)。非常感谢Rick。我真的不确定如何解决我的问题。我问了一个关于如何处理不断变化的工作负载的问题(即,当您有线程池正在使用队列时)…在评论中,您建议查看task_组,它似乎做了我想要做的事情(开销问题除外),因为parallel_for(我相信)需要提前知道需要做多少工作。我的工作量与这个问题非常相似(大量的小工作产生/消耗相同的队列)。使用tbb有更好的方法来实现设置吗?感谢timday这么多,你让我对parallel_do感兴趣。我对如何运行这个有点困惑。我是否首先给它一系列要处理的数据(从队列/列表中)然后使用进料器选项不断地向其添加更多的工作?并行任务是从指定的范围到并行任务,而不是像并行任务的“body”这样的实际范围是。这对单个任务的计算规模有一定的影响,否则开销将占主导地位。从最小化每个任务的开销的角度来看,安东在你的另一个问题上的乒乓并行可能是许多小任务的更好解决方案。