2

我可能没有正确测量这个,但我有一些我正在玩的简单代码。我不认为它是一个线程池,因为如果我使工作单元非常大,那么 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 场免费)。经济放缓可能与此有关吗?另外为什么这个程序会占用所有内存?它将它存储在内存中是什么,如果我只是调用线程,是不是有一个队列告诉它运行多少次,或者它是否将整个线程保存在内存中运行?

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

4

2 回答 2

4

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

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

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

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

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

-瑞克

于 2012-05-15T17:34:20.210 回答
2

只是为了强调 Rick 的最后一点,state的文档task_group

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

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

设计你的算法,使主体经常添加不止一项工作。...为了实现加速, B::operator() 的粒度需要至少约为 100,000 个时钟周期。否则,parallel_do 的内部开销会淹没有用的工作。

如果您正在寻找重要的 TBB 示例(超出parallel_for教程等),TBB模式手册非常好。

于 2012-05-15T19:37:01.520 回答