并发::parallel_fo(PPL)创建的线程太多
Concurrency::parallel_for (PPL) is creating too many threads
我使用Visual Studio 2010的并行模式库(PPL)的Concurrency::parallel_for()
来处理一组索引任务(通常,索引集远大于可以同时运行的线程数)。在进行长时间计算之前,每个任务都会从共享资源管理器请求一个专用的工作存储资源开始(在这种情况下:一个特定于任务的内存映射文件的视图,但我认为如果每个任务都从共享堆请求一个私有内存分配,情况会是一样的)。
共享资源管理器的使用与Concurrency::critical_section
同步,问题就从这里开始了:如果第一个线程/任务在关键部分,而第二个任务发出请求,它必须等到第一个任务的请求得到处理。PPL显然认为:嘿,这个线程正在等待,还有更多的任务要做,因此创建了另一个线程,导致多达870个线程在同一资源管理器中等待。
现在,由于处理资源请求只是整个任务的一小部分,我想告诉该部分的PPL要稳住阵脚,任何等待或协作块都不应该导致新线程从工作线程的指示部分开始,我的问题是:如果以及如何阻止特定线程部分创建新线程,即使它协同阻止。我不介意在线程处理路径的其他块上创建新线程,但也不介意超过2*(超)核的数量。
到目前为止,我已经考虑过的替代方案:
-
将任务排队,并从有限数量的线程中处理队列。问题:我希望PPL的parallel_fo能自己做到这一点。
-
定义一个
Concurrency::combinable<Resource> resourceSet
;在CCD_ 4外部初始化CCD_。问题:这种优化并不能阻止多余的线程创建。 -
为
parallel_for
循环之外的每个任务预先分配所需的资源。问题:这会请求太多的系统资源,而将资源量限制在线程/内核的数量是可以的(如果没有爆炸的话)。
我读过http://msdn.microsoft.com/en-us/library/ff601930.aspx,部分"不要在并行循环中重复阻塞",但遵循这里的建议将导致根本没有并行线程。
我不知道是否可以将PPL/ConcRT配置为不使用协作同步,或者至少限制它创建的线程数量。我认为它可能通过调度器策略来控制,但似乎没有一个策略参数适合这个目的。
然而,我有一些建议,你可能会发现有助于缓解问题,即使不是以理想的方式:
-
使用非协作同步原语来保护资源管理器,而不是
critical_section
。我认为(尽管没有检查)经典的WinAPICRITICAL_SECTION
应该会成功。作为朝着这个方向迈出的重要一步,您可以考虑为您的代码使用其他并行库;例如,Intel的TBB提供了大部分PPL API,并提供了更多(免责声明:我隶属于它)。 -
在并行循环之外预先分配一些资源。每个任务不需要一个资源;每个线程一个就足够了。将这些资源放入
concurrent_queue
中,然后在任务内部从队列中弹出一个资源,使用,然后将其推回。此外,线程可能会将资源囤积在combinable
对象中,以便在其他任务中重用,而不是将资源返回到队列。如果队列碰巧是空的(例如,如果PPL超额订阅了机器),可能会有不同的方法,例如在循环中旋转,直到某个其他线程返回资源,或者向管理器请求另一个资源。此外,您可以选择预先分配比线程数量更多的资源,以最大限度地减少资源耗尽的机会。
我的答案不是使用PPL的"解决方案",但我认为使用像taskqueue这样的线程池可以很容易地做到这一点,你应该看看这个答案。
所以你用你的作品填满了队列,它确保了不会有超过"x"个任务并行工作,其中x是boost::thread::hardware_concurrency()
(是的,再次提升…)
- 在没有太多条件句的情况下,我如何避免被零除
- 错误:字符数组的初始值设定项太多
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 对象实例化调用构造函数的次数太多
- Levenshtein 两个文件的距离花费了太多时间
- 我有三个 getline,但是一旦编译,输入就太多了
- 将使用太多的纹理插值器 - 带旋转的着色器
- C/C++:socket() 创建在循环中失败,打开的文件太多
- 使用Visual Studio在虚幻引擎中创建一个新的类c ++给了我太多的错误
- C++:数组<>初始值设定项太多
- 如何创建具有多个值的多个变量
- GLib-ERROR:为GWakeup创建管道:打开的文件太多
- C++,从文件读取到结构,然后读取到向量(结构被推入向量太多次,而不仅仅是一次)
- 为什么 std::remove_if 会创建如此多的闭包?
- 我会导致太多内存泄漏,以至于我的计算机无响应吗?
- 在重载函数的函数参数中使用右值引用会创建太多组合
- 并发::parallel_fo(PPL)创建的线程太多
- 我可以在Visual Studio 2012中编译和调试(运行)单个c++文件吗?(如何避免创建太多项目)
- parallel_for创建了太多的类/体副本
- 在类中创建运算符+而不声明太多不必要的变量的最佳方法