我尝试通过octave创建一个测试代码来评估我的8核处理器的Windows机器上的时间效率(单机并行);从文档中提供的简单代码示例开始,如下:
pkg load parallel
fun = @(x) x^2;
vector_x = 1:20000;
# Serial Format of the Program
tic()
for i=1:20000
vector_y(1,i)=vector_x(1,i)^2;
endfor
toc()
# Parallel Format of the Program
tic()
vector_y1 = pararrayfun(nproc, fun, vector_x);
toc()
令我惊讶的是,串行代码所需的时间比使用并行功能快得多。串行案例的运行时间为 0.0758219 秒,并行案例的运行时间为 3.79864 秒。
有人可以解释一下它是否是并行开销,或者我应该在我的 Octave 设置中设置一些东西,或者在哪些情况下并行化真的很有帮助?
TL;DR:在计时器之外打开你的泳池并选择更困难的操作。
有两个主要问题。其中之一是 Ander 在他的评论中提到的,启动并行池需要一两秒。您可以提前打开它(在 MATLAB 中,您可以通过
parpool
来完成此操作)以加快速度。或者,运行单个并行操作,从而打开池,然后重做计时。
第二个问题是操作的简单性。仅仅对一个数字进行平方不会比串行计算快得多。对于如此简单的操作,在工作人员之间来回传递数据是没有意义的。使用更昂贵的函数重做测试,例如
eig()
正如 MATLAB 在其示例中所做的那样。
因此,如果操作的运行时间大大超过了将数据传入和传出工作线程的开销,那么并行化就非常有用。基本上,这意味着您要么拥有一个非常大的数据集,需要对每个项目执行相同的操作(例如,取每 1000 行左右的平均值),要么您有一些繁重但独立的任务需要执行。
为了更深入的解释,我可以推荐我的这个答案以及其中的参考文献。
作为旁注,我很惊讶你的序列
for
这么快,因为你没有初始化你的输出向量。 预分配非常重要,因为在循环中“增长”数组需要创建一个新数组并将所有先前的内容复制到其中每次迭代。i
或 j
作为变量名称,因为它们表示虚数单位。它不会对运行时产生太大影响,但可能会导致很难调试的错误。只需使用 idx
、ii
或更具描述性的变量名称即可。
请注意,如上所示的 for 循环还有另一个问题:它将为动态增长的数组分配内存。您可以通过提前为输出数组分配内存来节省一些时间,例如
向量_y = 零(大小(向量_x));
循环之前。但该任务最简单、最快的解决方案是
向量_y =向量_x .^ 2; %。表示元素明智操作
与循环相比快 1000 倍!