Matrix Julia pmap速度-并行处理-动态规划

Matrix Julia pmap速度-并行处理-动态规划,matrix,parallel-processing,julia,dynamic-programming,pmap,Matrix,Parallel Processing,Julia,Dynamic Programming,Pmap,我试图加快Julia(v0.6.0)中动态规划问题的矩阵填充速度,而使用pmap似乎无法获得更多的速度。这与我一年前发布的一个问题有关:。我当时能够在很大的帮助下加速串行处理,现在我正试图从Julia中的并行处理工具中获得额外的速度 对于串行处理案例,我使用了一个三维矩阵(基本上是一组大小相等的矩阵,按第一维索引)并在第一维上迭代。不过,我想尝试一下pmap,以便更有效地迭代矩阵集 下面是代码设置。为了将pmap与下面的v_iter函数一起使用,我将三维矩阵转换为一个字典对象,字典键等于第一维中

我试图加快Julia(v0.6.0)中动态规划问题的矩阵填充速度,而使用
pmap
似乎无法获得更多的速度。这与我一年前发布的一个问题有关:。我当时能够在很大的帮助下加速串行处理,现在我正试图从Julia中的并行处理工具中获得额外的速度

对于串行处理案例,我使用了一个三维矩阵(基本上是一组大小相等的矩阵,按第一维索引)并在第一维上迭代。不过,我想尝试一下
pmap
,以便更有效地迭代矩阵集

下面是代码设置。为了将
pmap
与下面的
v_iter
函数一起使用,我将三维矩阵转换为一个字典对象,字典键等于第一维中的索引值(
v_dict
在下面的代码中,gcc等于第一维大小)。
v_iter
函数将其他字典对象(
E_opt_dict
gridpoint_m_dict
以下)作为附加输入:

function v_iter(a,b,c)
   diff_v = 1
   while diff_v>convcrit
     diff_v = -Inf

     #These lines efficiently multiply the value function by the Markov transition matrix, using the A_mul_B function
     exp_v       = zeros(Float64,gkpc,1)
     A_mul_B!(exp_v,a[1:gkpc,:],Zprob[1,:])
     for j=2:gz
       temp=Array{Float64}(gkpc,1)
       A_mul_B!(temp,a[(j-1)*gkpc+1:(j-1)*gkpc+gkpc,:],Zprob[j,:])
       exp_v=hcat(exp_v,temp)
     end    

     #This tries to find the optimal value of v
     for h=1:gm
       for j=1:gz
         oldv = a[h,j]
         newv = (1-tau)*b[h,j]+beta*exp_v[c[h,j],j]
         a[h,j] = newv
         diff_v = max(diff_v, oldv-newv, newv-oldv)
       end
     end
   end
end

gz =  9  
gp =  13  
gk =  17  
gcc =  5  
gm    = gk * gp * gcc * gz
gkpc  = gk * gp * gcc
gkp = gk*gp
beta  = ((1+0.015)^(-1))
tau        = 0.35
Zprob = [0.43 0.38 0.15 0.03 0.00 0.00 0.00 0.00 0.00; 0.05 0.47 0.35 0.11 0.02 0.00 0.00 0.00 0.00; 0.01 0.10 0.50 0.30 0.08 0.01 0.00 0.00 0.00; 0.00 0.02 0.15 0.51 0.26 0.06 0.01  0.00 0.00; 0.00 0.00 0.03 0.21 0.52 0.21 0.03 0.00 0.00 ; 0.00 0.00  0.01  0.06 0.26 0.51 0.15 0.02 0.00 ; 0.00 0.00 0.00 0.01 0.08 0.30 0.50 0.10 0.01 ; 0.00 0.00 0.00 0.00 0.02 0.11 0.35 0.47 0.05; 0.00 0.00 0.00 0.00 0.00 0.03 0.15 0.38 0.43]
convcrit = 0.001   # chosen convergence criterion

E_opt                  = Array{Float64}(gcc,gm,gz)    
fill!(E_opt,10.0)

gridpoint_m   = Array{Int64}(gcc,gm,gz)
fill!(gridpoint_m,fld(gkp,2)) 

v_dict=Dict(i => zeros(Float64,gm,gz) for i=1:gcc)
E_opt_dict=Dict(i => E_opt[i,:,:] for i=1:gcc)
gridpoint_m_dict=Dict(i => gridpoint_m[i,:,:] for i=1:gcc) 
对于并行处理,我执行了以下两个命令:

wp = CachingPool(workers())
addprocs(3)
pmap(wp,v_iter,values(v_dict),values(E_opt_dict),values(gridpoint_m_dict))
…产生这一性能的原因:

135.626417秒(3.29 G分配:57.152 GiB,3.74%gc时间)

然后,我尝试使用串行处理:

for i=1:gcc
    v_iter(v_dict[i],E_opt_dict[i],gridpoint_m_dict[i])
end
…并获得了更好的性能

128.263852 seconds (3.29 G allocations: 57.101 GiB, 4.53% gc time)
这也为我提供了与在原始三维对象上运行
v_iter
相同的性能:

v=zeros(Float64,gcc,gm,gz)
for i=1:gcc
    v_iter(v[i,:,:],E_opt[i,:,:],gridpoint_m[i,:,:])
end

我知道并行处理需要设置时间,但当我增加
gcc
的值时,串行和并行处理的处理时间仍然是相等的。这似乎是并行处理的一个很好的候选者,因为工作人员之间不需要消息传递!但我似乎无法使其高效工作。

在添加辅助进程之前,您创建了
CachingPool
。因此,传递给
pmap
的缓存池告诉它只使用一个工作进程。 您可以通过运行
wp.workers
来检查它,您将看到类似
Set([1])
的内容。 因此,它应该是:

addprocs(3)
wp=CachingPool(workers())
您还可以考虑运行朱丽亚<代码> -p/COD>命令行参数,例如“代码>朱丽亚-P 3 ”,然后可以跳过<代码> AddiPro(3)命令。 除此之外,您的
for
pmap
循环并不等效。Julia
Dict
对象是一个hashmap,与其他语言类似,它不提供元素顺序。因此,在for循环中,保证获得相同的匹配
i
-th元素,而使用
值时,值的顺序不需要与原始顺序匹配(并且在
pmap
循环中,这三个变量的顺序可以不同)。 由于
Dicts
的键只是从
1
gcc
的数字,因此您只需使用数组即可。您可以使用非常类似于Python的生成器。例如,代替

v_dict=dict(对于i=1:gcc,i=>0(Float64,gm,gz)
使用

v_dict_a=[零(Float64,gm,gz)表示i=1:gcc]


希望能有所帮助。

基于@Przemyslaw Szufeul的有用建议,我在下面列出了正确执行并行处理的代码。在运行一次之后,我在运行时间上取得了实质性的改进:
77.728264秒(181.20 k分配:12.548 MiB)

除了对
wp
命令重新排序并使用推荐的生成器Przemyslaw外,我还将
v_iter
作为一个匿名函数进行了重新编写,以避免在代码周围到处散布
@
,从而将函数和数据提供给工作人员

我还向
v_iter
函数添加了
returna
,并将
v_a
设置为等于
pmap
的输出,因为您无法通过引用传递到远程对象

addprocs(3)
v_iter = function(a,b,c)
   diff_v = 1
   while diff_v>convcrit
     diff_v = -Inf

     #These lines efficiently multiply the value function by the Markov transition matrix, using the A_mul_B function
     exp_v       = zeros(Float64,gkpc,1)
     A_mul_B!(exp_v,a[1:gkpc,:],Zprob[1,:])
     for j=2:gz
       temp=Array{Float64}(gkpc,1)
       A_mul_B!(temp,a[(j-1)*gkpc+1:(j-1)*gkpc+gkpc,:],Zprob[j,:])
       exp_v=hcat(exp_v,temp)
     end    

     #This tries to find the optimal value of v
     for h=1:gm
       for j=1:gz
         oldv = a[h,j]
         newv = (1-tau)*b[h,j]+beta*exp_v[c[h,j],j]
         a[h,j] = newv
         diff_v = max(diff_v, oldv-newv, newv-oldv)
       end
     end
   end
  return a
end

gz =  9  
gp =  13  
gk =  17  
gcc =  5  
gm    = gk * gp * gcc * gz
gkpc  = gk * gp * gcc
gkp   =gk*gp
beta  = ((1+0.015)^(-1))
tau        = 0.35
Zprob = [0.43 0.38 0.15 0.03 0.00 0.00 0.00 0.00 0.00; 0.05 0.47 0.35 0.11 0.02 0.00 0.00 0.00 0.00; 0.01 0.10 0.50 0.30 0.08 0.01 0.00 0.00 0.00; 0.00 0.02 0.15 0.51 0.26 0.06 0.01  0.00 0.00; 0.00 0.00 0.03 0.21 0.52 0.21 0.03 0.00 0.00 ; 0.00 0.00  0.01  0.06 0.26 0.51 0.15 0.02 0.00 ; 0.00 0.00 0.00 0.01 0.08 0.30 0.50 0.10 0.01 ; 0.00 0.00 0.00 0.00 0.02 0.11 0.35 0.47 0.05; 0.00 0.00 0.00 0.00 0.00 0.03 0.15 0.38 0.43]
convcrit = 0.001   # chosen convergence criterion

E_opt                  = Array{Float64}(gcc,gm,gz)    
fill!(E_opt,10.0)

gridpoint_m   = Array{Int64}(gcc,gm,gz)
fill!(gridpoint_m,fld(gkp,2)) 

v_a=[zeros(Float64,gm,gz) for i=1:gcc]
E_opt_a=[E_opt[i,:,:] for i=1:gcc]
gridpoint_m_a=[gridpoint_m[i,:,:] for i=1:gcc]

wp = CachingPool(workers())
v_a = pmap(wp,v_iter,v_a,E_opt_a,gridpoint_m_a)

亲爱的@user1534219您的代码非常长,在这里提供答案对其他人没有用处。您能否仅过滤出与您的问题相关的部分(例如,通过提供一个10行的基本示例,而不是您现在拥有的近200行)Hi-Przemyslaw Szufel,感谢您的输入。我对代码进行了相当大的编辑,只需输入
Zprob
马尔可夫转移矩阵的值,而不是构建该矩阵的函数……性能发生了一些变化,因为我对该矩阵中的数字进行了四舍五入。我还将“动态规划”添加到问题标题中,以便读者了解问题的焦点。动态规划问题在经济学、金融学和运筹学中非常常见。非常感谢您的及时回复!我真的很感激。我一定会尝试一下这些建议。至于散列…我想使用
pmap
在矩阵集合上循环,这样每个矩阵都可以单独修改。我认为
Dict
对象是构建此集合的方法,但您的回答表明这是错误的。你有没有其他的建议?如果可能的话,我想避免使用
ShareDarray
,特别是因为工作人员之间不需要发送消息。@user1534219,我编辑了响应。避免共享Darrays始终是一个好主意,因为它会给代码带来极大的复杂性。Przemyslaw Szufel,谢谢你的帮助!!在并行处理中,我使用您建议的生成器将时间缩短到54秒,而在串行处理中则是125秒。我所做的唯一额外更改是根据此处的建议,将
v_iter
函数设置为匿名函数:;否则,我将不得不在代码周围到处撒
,以收取费用