4

我正在使用Concurrency::parallel_for()Visual Studio 2010 的并行模式库 (PPL) 来处理一组索引任务(通常,索引集远大于可以同时运行的线程数)。每个任务,在进行冗长的计算之前,首先从共享资源管理器请求一个私有的工作存储资源(以防:查看任务特定的内存映射文件,但我认为如果每个任务的故事情节是相同的从共享堆请求私有内存分配)。

共享资源管理器的使用与 a 同步,Concurrency::critical_section这里问题开始了:如果第一个线程/任务在临界区并且第二个任务发出请求,它必须等到第一个任务的请求被处理。PPL 显然会想:嘿,这个线程正在等待,还有更多任务要做,因此创建了另一个线程,导致多达 870 个线程主要在同一个资源管理器处等待。

现在,由于处理资源请求只是整个任务的一小部分,我想告诉 PPL 在该部分保持其马匹,任何等待或协作块都不应该导致新线程从指定部分开始工作线程,我的问题是:我是否以及如何阻止特定线程部分创建新线程,即使它合作阻塞。我不介意在线程处理路径下方的其他块中创建新线程,但不会超过 2*(超)核心数。

到目前为止我考虑过的替代方案:

  1. 排队任务并从有限数量的线程处理队列。问题:我希望 PPL 的 parallel_for 能够自行完成。

  2. 定义一个Concurrency::combinable<Resource> resourceSetConcurrency::parallel_for和初始化一次resourceSet.local()以减少资源请求的数量(通过重用资源)到线程的数量(应该小于任务的数量)。问题:此优化不会阻止多余的线程创建。

  3. parallel_for为循环外的每个任务预先分配所需的资源。问题:这将请求过多的系统资源,而将资源量限制为线程/内核的数量是可以的(如果没有爆炸的话)。

我阅读了http://msdn.microsoft.com/en-us/library/ff601930.aspx的“不要在并行循环中重复阻塞”部分,但遵循此处的建议将导致根本没有并行线程。

4

2 回答 2

4

我不知道是否可以将 PPL/ConcRT 配置为不使用协作同步,或者至少限制它创建的线程数。我认为它可以通过调度程序策略进行控制,但似乎没有任何策略参数适合此目的。

但是,即使不是以理想的方式,我也有一些您可能会发现对缓解问题有用的建议:

  • 代替critical_section,使用非合作同步原语来保护资源管理器。我认为(虽然没有检查)经典的WinAPICRITICAL_SECTION应该成功。作为朝着这个方向迈出的重要一步,您可以考虑为您的代码使用其他并行库;例如,英特尔的 TBB 提供了大部分 PPL API 并且有更多(免责声明:我隶属于它)。

  • 在并行循环之外预先分配一些资源。每个任务不需要一个资源;每个线程一个就足够了。将这些资源放入一个concurrent_queue,并在一个任务中从队列中弹出一个资源,使用,然后将其推回。此外,不是将资源返回到队列,一个线程可能会将其存储在一个combinable对象中,以便在其他任务中重用。如果队列恰好是空的(例如,如果 PPL 超额订阅了机器),可能会有不同的方法,例如循环旋转直到某个其他线程返回资源,或者从管理器请求另一个资源。此外,您可以选择预先分配比线程数更多的资源,以最大程度地减少资源耗尽的机会。

于 2014-09-30T21:27:18.560 回答
1

我的答案不是使用 PPL 的“解决方案”,但我认为您可以使用taskqueue之类的线程池轻松做到这一点,您应该看看这个答案

所以你用你的作品填满队列,它确保不会有超过“x”个任务并行工作,其中 x 是boost::thread::hardware_concurrency()(是的,再次提升......)

于 2014-10-01T14:26:31.540 回答