C ++ 11在多个线程中执行成对计算的最佳方法是什么?我的意思是,我有vector
个元素,我想为每对不同的元素计算一个函数。需要注意的是,我不能同时在多个线程中使用相同的元素,例如元素具有在计算过程中发展的状态,并且计算依赖于此。
答案 0 :(得分:2)
一种简单的方法是按偏移对对进行分组。
如果v是向量,则元素N apart(mod v.size())形成两个对的集合。这些对中的每一对都不包含内部重叠。
检查10个元素向量0 1 2 3 4 5 6 7 8 9
。分开的1对是:
0 1, 1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 8, 8 9, 9 0
如果你将这些分成"奇偶校验"我们得到两个集合:
0 1, 2 3, 4 5, 6 7, 8 9
1 2, 3 4, 5 6, 7 8, 9 0
您可以并行处理上述每个集合。收集完成后,同步,然后处理下一个集合。
类似的技巧可以分开2个。
0 2, 1 3, 4 6, 5 7
2 4, 3 5, 6 8, 7 9
剩菜:
8 0, 9 1
对于从1到n / 2的每个偏移量,都有2个"集合"和剩菜。
这是4的补偿:
0 4, 1 5, 2 6, 3 7
4 8, 5 9, 6 0, 7 1
和剩饭剩菜
8 2, 9 3
(我天真地认为剩菜的大小是矢量大小mod偏移)
计算这些收藏品(以及残羹剩饭)并不难;安排排队线程并在正确的线程中有效地完成正确的任务更难。
有N选择2,或(n ^ 2 + n)/ 2,对。这个分割为你提供了O(1.5n)集合和剩余物,每个集合的大小最多为n / 2,并且每个集合中都有完全并行性。
如果你的某些元素比其他元素贵得多,并因此等待每个集合完成过多的空闲线程,你可以添加细粒度的同步。
保持原子布尔的矢量。用它来表示您当前正在处理元素。永远"锁定" (设置为true,并在将其设置为true之前检查它是否为false)在较高索引之前的较低索引。
如果您设法锁定两者,请将其处理掉。然后清除它们。
如果您失败,请记住以后的任务,并处理其他任务。如果排队的任务太多,请等待条件变量,尝试检查并设置要锁定在spin-lambda中的原子bool。
清除锁定时,定期启动条件变量。您这样做的频率取决于分析。您可以在不查询互斥锁mayhap的情况下踢(但有时必须在清除bool之后获取互斥锁以处理可能使线程饿死的竞争条件)。
按照上述收集系统指示的顺序对任务进行排队,因为这样可以减少线程冲突的可能性。但是使用这个系统,即使有一项任务落后,工作仍然可以进展。
它增加了复杂性和同步性,这很容易使它比纯粹的集合/同类组件慢。