Julia @parallel for return with return statement

Osk*_*ar 7 parallel-processing for-loop julia

如何在满足条件的情况下为所有工作人员返回的函数中编写并行for循环?

就是这样的:

function test(n)
  @sync @parallel for i in 1:1000
    {... statement ...}
    if {condition}
      return test(n+1)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

所有工人都停止在for循环上工作,只有主进程返回?(其他进程再次开始使用下一个for循环?)

Dan*_*etz 3

这个问题似乎是执行“令人尴尬的并行”搜索任务的基本模式。该@parallel for构造非常适合分区工作,但不具有用于停止单个流程的break短路逻辑。for

为了演示如何在 Julia 中执行此操作,请考虑一个寻找密码锁与多个轮子的组合的玩具问题。可以通过某种方法检查轮子的每个设置是否正确(需要一些combodelay时间 - 请参阅下面的代码)。找到正确的轮子编号后,将搜索下一个轮子。高级伪代码就像OP问题中给出的片段。

以下是运行代码(在 0.5 和 0.6 上)来执行此操作。一些注释解释了细节,并且代码以单个块的形式给出,以便于剪切和粘贴。

# combination lock problem parameters
const wheel_max = 1000  # size of wheel
@everywhere const magic_number = [55,10,993]  # secret combination
const wheel_count = length(magic_number)  # number of wheels
const combodelay = 0.01 # delay time to check single combination

# parallel short-circuit parameters
const check_to_work_ratio = 160  # ratio to limit short-circuit overhead

function find_combo(wheel,combo=Int[])
  done = SharedArray{Int}(1)       # shared variable to hold if and what combo
  done[1] = 0                      #  succeded. 0 means not found yet
  # setup counters to limit parallel overhead
  @sync begin
    @everywhere global localdone = false
    @everywhere global checktime = 0.0
    @everywhere global worktime = 0.0
  end
  # do the parallel work
  @sync @parallel for i in 1:wheel_max
    global localdone
    global checktime
    global worktime
    # if not checking too much, look at shared variable
    if !localdone && check_to_work_ratio*checktime < worktime
      tic()
      localdone = done[1]>0
      checktime += toq()
    end
    # if no process found combo, check another combo
    if !localdone
      tic()
      sleep(combodelay) # simulated work delay, {..statement..} from OP
      if i==magic_number[wheel]    # {condition} from OP
        done[1] = i              
        localdone = true
      end
      worktime += toq()
    else
      break
    end
  end
  if done[1]>0 # check if shared variable indicates combo for wheel found
    push!(combo,done[1])
    return wheel<wheel_count ? find_combo(wheel+1,combo) : (combo,true)
  else
    return (combo,false)
  end
end

function find_combo_noparallel(wheel,combo=Int[])
  found = false
  i = 0
  for i in 1:wheel_max
    sleep(combodelay)
    if i==magic_number[wheel]
      found = true
      break
    end
  end
  if found
    push!(combo,i)
    return wheel<wheel_count ? 
      find_combo_noparallel(wheel+1,combo) : (combo,true)
  else
    return (combo,false)
  end
end

function find_combo_nostop(wheel,combo=Int[])
  done = SharedArray{Int}(1)
  done[1] = 0
  @sync @parallel for i in 1:wheel_max
    sleep(combodelay)
    if i==magic_number[wheel]
      done[1] = i
    end
  end
  if done[1]>0
    push!(combo,done[1])
    return wheel<wheel_count ? 
      find_combo_nostop(wheel+1,combo) : (combo,true)
  else
    return (combo,false)
  end
end

result = find_combo(1)
println("parallel with short-circuit stopping:       $result")
@assert result == (magic_number, true)

result = find_combo_noparallel(1)
println("single process with short-circuit stopping: $result")
@assert result == (magic_number, true)

result = find_combo_nostop(1)
println("parallel without short-circuit stopping:    $result")
@assert result == (magic_number, true)

println("\ntimings")

print("parallel with short-circuit stopping        ")
@time find_combo(1);
print("single process with short-circuit stopping  ")
@time find_combo_noparallel(1)
print("parallel without short-circuit stopping     ")
@time find_combo_nostop(1)

nothing
Run Code Online (Sandbox Code Playgroud)

可能会有更好看的实现,并且一些元编程可以隐藏一些短路机制。但这应该是一个好的开始。

结果应大致如下所示:

parallel with short-circuit stopping:       ([55,10,993],true)
single process with short-circuit stopping: ([55,10,993],true)
parallel without short-circuit stopping:    ([55,10,993],true)

timings
parallel with short-circuit stopping          4.473687 seconds
single process with short-circuit stopping   11.963329 seconds
parallel without short-circuit stopping      11.316780 seconds
Run Code Online (Sandbox Code Playgroud)

这是针对 3 个工作进程的演示而计算的。真正的问题应该有更多的进程,每个进程有更多的工作,然后短路的好处就会很明显。