【问题标题】:Thread IDs with PPL and Parallel Memory Allocation具有 PPL 和并行内存分配的线程 ID
【发布时间】:2012-04-03 09:15:55
【问题描述】:

我有一个关于 Microsoft PPL 库和一般并行编程的问题。我正在使用 FFTW 执行大量(100,000)64 x 64 x 64 FFT 和逆 FFT。在我当前的实现中,我使用并行 for 循环并在循环内分配存储数组。我注意到在这些情况下,我的 CPU 使用率最高只有 60-70%。 (请注意,这仍然比我测试过的 FFTW 提供的内置线程 FFT 更好地利用)。由于我使用的是 fftw_malloc,是否有可能发生过度锁定而导致无法完全使用?

鉴于此,是否建议在主处理循环之前为每个线程预先分配存储数组,这样循环本身就不需要锁?如果是这样,MSFT PPL 库怎么可能做到这一点?我以前一直在使用 OpenMP,在这种情况下,使用提供的函数获取线程 ID 很简单。但是,我在 PPL 文档中没有看到类似的功能。

【问题讨论】:

    标签: c++ multithreading openmp fftw ppl


    【解决方案1】:

    我只是回答这个问题,因为还没有人发布任何内容。

    如果需要大量锁定,Mutex(e) 可能会对性能造成严重破坏。此外,如果需要大量内存(重新)分配,这也会降低性能并将其限制为内存带宽。就像您说的那样,稍后线程操作的预分配可能很有用。但是,这要求您有一个固定的线程数,并且您将工作负载均衡地分布在所有线程上。

    关于 PPL thread_id 函数,我只能说 Intel-TBB,不过它应该与 PPL 非常相似。 TBB - 我想 PPL 也不是直接谈论线程,而是他们谈论任务,TBB 的目的是从用户那里抽象出这些底层细节,因此它不提供 thread_id 函数。

    【讨论】:

    • 感谢您的快速回复。我同意你的看法,瓶颈似乎与大量的内存分配有关;随着 FFT 大小的减小,相对并行加速增加(例如,16x16x16 提供了几乎线性加速与核心和 100% 利用率)。知道 PPL 是一个基于任务的框架,你知道有什么方法可以为每个任务分配内存吗? (不一定是每个循环迭代,就像现在所做的那样)基本上,每个线程/任务都有一组动态分配的私有数据。
    • 对于我对这些框架的幼稚,我提前道歉;我的背景是工程,而不是 CS。
    • @KyleLynch 好吧,假设你的工作量是平衡的,我可以考虑以下几点:保持粒度尽可能大,然后在你的工作人员循环之前分配内存。编辑:我刚刚检查了 ppl::parallel_for ,界面确实与 tbb 有点不同。此处 TBB 的优势在于您可以更好地使用范围。对于 PPL 中的相同行为,您可能必须编写一个包装函数。我希望代码能解释我的意思。 pastebin.com/Tg4FL6KB
    • 非常感谢!你的建议很有帮助。我还能够通过此链接找到一种使用 PPL 更好地控制粒度的方法:msdn.microsoft.com/en-us/library/gg663527.aspx 现在效果更好。
    【解决方案2】:

    使用 PPL,我通过使用 Concurrency::combinable 保存包含每个线程分配的内存的结构来执行大量分配的应用程序具有良好的性能。

    事实上,您不必预先分配,您可以使用->local() 检查可组合变量的值,如果它为空,则分配它。下次调用这个线程时,它已经被分配了。

    当然,您必须在所有任务完成后释放内存,这可以使用以下方法完成: 类似于:

    combine_each([](MyPtr* p){ delete p; });
    

    【讨论】:

    • 或使用 Concurrency::combinable> resourceSet;并使用 if (!resourceSet.local()) resourceSet.local() = std::make_unique(...);
    猜你喜欢
    • 2010-09-28
    • 1970-01-01
    • 2010-10-21
    • 2018-12-10
    • 1970-01-01
    • 2017-04-05
    • 2019-06-25
    • 2018-10-21
    • 2013-04-14
    相关资源
    最近更新 更多