在下面的代码片段中,如果你用ParallelDo替换Do,它将以3 SLOWER的系数计算,因为现在循环只会在两个内核中的一个中断。
ParallelEvaluate[NN = 10070];
SetSharedVariable[res]
Module[{a, b, c},
Do[
c = NN - a - b;
If[a a + b b == c c, res = a b c; Break[]]
, {a, 1, NN}, {b, a + 1, NN}
];
res
] // AbsoluteTiming
调用ParallelAbort可以解决问题,但这是禁止的。还有什么?
答案 0 :(得分:4)
您需要为每次迭代指明方法 找到答案的所有其他迭代。 我使用“退出”标志对其进行建模,最初设置 为false,在任何迭代时设置为true 决定完成。每次迭代同样具有 检查退出条件。
我的Mathematica生锈了15年,我没有 之前见过Parallelxxx形式,但是很好的猜测 循环应该如何改变如下 代码的变化:
ParallelEvaluate[NN = 10070];
SetSharedVariable[res,quit]
Module[{a, b, c},
quit=false;
Do[ c = NN - a - b;
If[quit, Break[]];
If[ a a + b b == c c, quit=true; res = a b c; Break[]],
{a, 1, NN}, {b, a + 1, NN}
];
res
] // AbsoluteTiming
额外的If在某种程度上减慢了循环,但这就是价格 同步。
我怀疑金额 你在每次迭代中所做的工作已经很小了 与并行执行每次迭代的成本相比, 所以这个循环可能是低效的,你可能得不到 Do Parallel的任何实际价值。 如果你不这样做,那么你可以使每个Do迭代操作几个值 a和b的一个(例如,使用{a,1,NN,10},并且对于每个都使用类似的b) 迭代并将10宽子范围作为子循环处理 每次并行迭代)。相比之下,保持退出测试退出开销很小 在每个循环体中完成的工作。 为读者留下了重新训练的运动。
您的代码还有另一个问题:设置中存在竞争条件 水库。在ceratin情况下,两次迭代都可以决定设置res。 如果您不关心产生哪个答案,并且res的商店是“原子”, 这可以。如果res是更复杂的数据结构,则更新 它花了多个Mathematica语句,你肯定会有数据竞争 并且你的循环会在很长一段时间内产生糟糕的结果 调试会非常困难。理想情况下,你需要某种原子 测试以保护退出条件。我不知道MMa是什么, 所以你必须要查找它,但我想象一个“原子[...]”形式 坚持认为它的主体只由许多并行线程中的一个执行。 (也许MMa有一个可以用来实现原子的信号量]。 如果是这样,那么您的代码应如下所示:
ParallelEvaluate[NN = 10070];
SetSharedVariable[res,quit]
Module[{a, b, c},
quit=false;
Do[ c = NN - a - b;
If[quit, Break[]];
If[ a a + b b == c c,
atomic[If[not[quit]; quit=true; res = a b c;]; Break[]],
{a, 1, NN}, {b, a + 1, NN}
];
res
] // AbsoluteTiming