Parallel processing 朱莉娅:并行代码比顺序代码慢,有没有替代remotecall()的方法?

Parallel processing 朱莉娅:并行代码比顺序代码慢,有没有替代remotecall()的方法?,parallel-processing,julia,Parallel Processing,Julia,当我并行运行一个简单的函数(每个工作程序有不同的输入)时,并行化版本代码所需的时间始终比顺序化版本代码所需的时间长 简单的函数是 addprocs(2) @everywhere function simple(i,Q,vt_0,ct_0) a=sum((rand(1:i),vt_0,ct_0))*2 return a end 我的代码的并行版本是 #In Parallel tic() N=10000; v=zeros(N); c=zeros(N); vt_0=0; ct_0=0; f

当我并行运行一个简单的函数(每个工作程序有不同的输入)时,并行化版本代码所需的时间始终比顺序化版本代码所需的时间长

简单的函数是

addprocs(2)
@everywhere function simple(i,Q,vt_0,ct_0)
  a=sum((rand(1:i),vt_0,ct_0))*2
  return a
end
我的代码的并行版本是

#In Parallel
tic()
N=10000;
v=zeros(N);
c=zeros(N);
vt_0=0;
ct_0=0;

for i=1:N

  v[i]=fetch(remotecall(simple,2,i,1,vt_0,ct_0))

  c[i]=fetch(remotecall(simple,3,i,2,vt_0,ct_0))

  vt_0=v[i]
  ct_0=c[i]

end
toc()
虽然顺序代码只是在循环的每次迭代中调用函数(没有
remotecall()
也没有
fetch()
),但我认为我在Julia中使用
remotecall()
并行调用worker的方式是问题的根源,但我不确定

有人能帮我弄明白为什么这个并行代码比只调用函数要慢吗?或者这个简单的计算不值得并行吗

编辑:
以下是顺序代码:

#Sequential
tic()
N=10000;
v=zeros(N,2);
c=zeros(N,2);
vt_0=0;
ct_0=0;

for i=1:N

  v[i]=simple(i,1,vt_0,ct_0)

  c[i]=simple(i,2,vt_0,ct_0)

  vt_0=v[i]
  ct_0=c[i]
end
toc()

即使对于
simple()
内部非常“浅”的计算,Julia文档也建议使用
remotecall\u fetch()
而不是
fetch(remotecall(…)

函数
remotecall\u fetch()
就是为了这个目的而存在的。它相当于
fetch(remotecall(…)
,但效率更高


[并行]
-进程
@spawn
/
开销 这是一个经常被忽视的话题,积极认识并尝试对这个话题进行推理是很好的。实际上,这是对
[PARALLEL]
-进程调度最终性能产生不利影响的常见根本原因


这里的主要“可疑”是进程间依赖关系的值:
  • 其中一个可能隐藏在系统函数
    rand()
    中。如果使用了加密功能强大的实现,则每次调用
    rand())
    必须更新随机性的中心源“-状态。这意味着,由于这个特殊的原因,所有、实际上所有衍生的进程都必须建立并维护一个到该中心共享服务的队列,而该队列将根本不存在(因为它可能导致零随机性源“-状态更新问题)在一个简单的
    [SEQ]
    -代码执行中,但如果
    [PAR]
    -代码执行单元实际上“共享”了这个中心资源,则需要一些额外的隐藏开销(互斥锁/锁/值更新原子等)(被隐藏为严格的事务性,并发能力为1,操作1:N阻塞逻辑信号,无回滚…)并且必须执行并强制执行随机性源状态的原子安全更新,然后才能提供对随机性源服务的任何下一次调用

  • 另一个是{previor | next}-循环步骤依赖,这是对
    simple()
    -进程实例的调用之间再次相互交叉。如下图所示,这种相互依赖实际上使得所有可能产生的调用都必须被安排为纯
    [SEQ]
    -进程调度和“剩余的”
    总和()
    确实没有太多的肉可以咀嚼
    [并行]
    -流程计划


实际的进程间相互依赖关系图描述了至少注入循环
以使
[并行]
-处理更高效的可能性:
您是否在每个步骤的工作人员和请求者之间传输数据?我从CUDA回忆起,主机和工作人员之间的数据交换存在开销,为了弥补这一点,我们限制传输并最大化远程操作我不认为我在每个步骤的工作人员之间传输数据,但正如您所看到的,我更改了功能的输入每一步都是基于上一步。但是你将数据从请求代理传输到工作者,然后从工作者返回到请求代理,对吗?啊,我明白你的意思。是的,我相信这就是正在发生的事情。但是我不确定。这会是一个限制吗?是的,在并行处理中,你需要将计算带到数据不是相反的方式,因为数据移动比数据处理更昂贵,即使在网络上也是如此。因此,如果你能向员工发送更大的数据块,这将使事情变得更快、更周到、更有用。非常感谢你(是的,
Q
只是为了测试一些其他东西;忘了拿出来)Gunnar很高兴你认为这很重要而且很有帮助。如果你喜欢GUI工具和开销严格的模型,请毫不犹豫地访问AMDAHL法律重新制定和升级的链接帖子。BTW:你试过用<代码> RAND()来测试代码吗?
被替换以证明/拒绝共享随机性源的事务性开销?是的,我会告诉你结果。
//                           +-------------<---- a way to "inject" a for-loop
//                           |  +----------<---- NOT CONSUMED AT ALL
//                           |  |
//                           |  |             +--******* BUT ********* DEPENDENCY
//                           |  |             |
//                           |  |             v
//                           |  |  +-------<-->- v[]-{prior|next}-step DEPENDENCY
//                           |  |  |     +-<-->- c[]-{prior|next}-step DEPENDENCY
//                           |  |  |     |
//          function simple( i, Q, vt_0, ct_0 )
@everywhere function simple( N, Q, vt_0, ct_0, aVEC )
   for     i  = 1:N
      aVEC[i] = sum( (  rand(1:i), vt_0, ct_0 ) )*2
      //   a  = sum( (  rand(1:i), vt_0, ct_0 ) )*2
      // ret a
end
// ------------------------------------------------------------<SuT>-START
tic()
for i=1:N

  v[i]=fetch(remotecall(simple,2,i,1,vt_0,ct_0))
  c[i]=fetch(remotecall(simple,3,i,2,vt_0,ct_0))

  vt_0=v[i]
  ct_0=c[i]

end
toc()
// ------------------------------------------------------------<SuT>-FINISH