'new'和'delete'不像intel线程构建块scalable_malloc / free那样可扩展

时间:2012-02-15 07:04:47

标签: parallel-processing

要清楚,这不是tbb库的广告。我最近发现的东西让我很惊讶。

我在堆争用上做了一个小小的谷歌。而且似乎在glibc 2.3之后。 'new'和'delete'已得到改进,可以很好地支持多处理器。我的glibc是2.5。并遵循非常简单的代码。

tbb::tick_count t1 = tbb::tick_count::now();

    for (size_t i = 0; i < 100000; ++i)
    {
        char * str = new char [100];
        delete str;
    }
tbb::tick_count t2 = tbb::tick_count::now();
std::cout << "process time = " << (t2 - t1).seconds() << std::endl;

我有一个带有16个CPU内核的Linux机箱。我开始分别运行1和8个线程来运行代码。让我感到困惑的第一件事是,当有8个线程在运行时,处理时间较少。这对我没有意义。这怎么可能呢?

我做的其他测试是,代替上面的简单代码,每个线程运行一个非常复杂的算法,在算法期间,还有很多新的和删除。当线程数从1增加到8时,处理时间几乎增加了100%。

你可能会问我怎么知道它是'新'和'删除'导致时间增加,这是因为我用tbb的scalable_malloc / free替换'new'和'delete'后,处理时间只增加了5左右线程数从1增加到8时的%。

这对我来说是另一个谜,为什么'新'和'删除'不像以前的简单代码那样扩展。

另一个谜团是,如果我在每个线程运行的算法前面添加了前面的简单代码。然后,当我将线程数从1增加到8时,根本没有时间增加。

我对我的测试感到非常惊讶。有人可以给我的测试结果解释一下吗?非常感谢。

1 个答案:

答案 0 :(得分:1)

这根本不是一个谜。众所周知,多线程应用程序中的内存分配会增加线程阻塞时间(特别是,这种情况发生在Linux上的内核TASK_UNINTERRUPTIBLE状态中的休眠线程)。并且从堆中分配内存可能很快成为瓶颈,因为标准分配器通过序列化请求来处理来自多个线程的多个分配请求。这些是您遇到的性能下降的主要原因。当然,这反过来导致有效分配器的实现。你引用了TBB,但还有其他免费提供的选择。

例如,参见ThreadAlloc库,正如他的作者所说,“与使用动态内存分配密集的多线程应用程序的SMP平台上的标准分配器相比,性能提供了大约10倍的优势”。

另一个选项是Hoard