@ sync / @ async와 함께 Distributed 및 SharedArray를 사용하여 Julia 많은 할당

Sep 11 2020

julia와 병렬 작업을 수행하기 위해 SharedArrays와 함께 Distributed 패키지를 사용하는 방법을 이해하려고합니다. 예를 들어 간단한 Montecarlo 평균 방법을 사용합니다.

using Distributed 
using SharedArrays
using Statistics

const NWorkers = 2
const Ns = Int(1e6)


function parallelRun()

    addprocs(NWorkers)
    procsID = workers()

    A = SharedArray{Float64,1}(Ns)
    println("starting loop")

    for i=1:2:Ns
        #parallel block
        @sync for p=1:NWorkers
                @async A[i+p-1] = remotecall_fetch(rand,procsID[p]);
        end
    end

    println(mean(A))
end


function singleRun()
    A = zeros(Ns)
    for i=1:Ns
        A[i] = rand()
    end
 
    println(mean(A))
end

그러나 내가 두 기능을 모두 @time하면

julia> @time singleRun()
0.49965531193003165
  0.009762 seconds (17 allocations: 7.630 MiB)
julia> @time parallelRun()
0.4994892300029917
 46.319737 seconds (66.99 M allocations: 2.665 GiB, 1.01% gc time)

특히 병렬 버전에는 더 많은 할당이 있으므로 코드가 훨씬 느려집니다.

내가 뭔가를 놓치고 있습니까?

그건 그렇고 내가 @sync와 @async를 사용하는 이유는 (모든 샘플이 임의의 순서로 계산 될 수 있기 때문에이 프레임 워크에서 필요하지 않더라도) 동일한 전략을 적용하여 포물선 형 PDE를 수치 적으로 풀고 싶기 때문입니다. 줄에 뭔가

    for t=1:time_steps

        #parallel block
        @sync for p=1:NWorkers
                @async remotecall(make_step_PDE,procsID[p],p);
        end
    end

p에 의해 색인 된 각 작업자는 내 방정식의 분리 된 색인 세트에서 작업해야합니다.

미리 감사드립니다

답변

2 PrzemyslawSzufel Sep 11 2020 at 05:57

코드에 다음과 같은 문제가 있습니다.

  • a의 각 값에 대해 원격 작업을 생성하고 i있으며 이는 비용이 많이 들고 결국 시간이 오래 걸립니다. 기본적으로 경험상의 규칙은 @distributed작업자 간로드 밸런싱에 매크로 를 사용 하는 것입니다. 이렇게하면 작업이 균등하게 공유됩니다.
  • addprocs작업 함수를 실행할 때마다 새 프로세스를 추가 할 때마다 새 줄리아 프로세스를 생성하는데도 많은 시간이 걸리므로 작업 함수에 넣지 마십시오 . 실제로 이것은 addprocs초기화를 수행하는 스크립트의 일부 에서 실행 하거나 또는 매개 변수를 사용 하여 julia프로세스 를 시작하여 추가 된 프로세스를 의미합니다.-p --machine-file
  • 마지막으로 @time항상 두 번 실행 하십시오. 첫 번째 측정 @time에서는 컴파일 시간도 측정하고 분산 환경에서의 컴파일은 단일 프로세스보다 훨씬 오래 걸립니다.

당신의 기능은 다음과 같이 보일 것입니다.

using Distributed, SharedArrays
addprocs(4)
@everywhere using Distributed, SharedArrays
function parallelRun(Ns)
    A = SharedArray{Float64,1}(Ns)
    @sync @distributed for i=1:Ns
         A[i] = rand();
    end
    println(mean(A))
end

작업자간에 데이터를 완전히 분할하는 것도 고려할 수 있습니다. 일부 시나리오에서는 버그 발생 가능성이 적고 여러 노드에 배포 할 수 있습니다.

using Distributed, DistributedArrays
addprocs(4)
@everywhere using Distributed, DistributedArrays
function parallelRun2(Ns)
    d = dzeros(Ns) #creates an array distributed evenly on all workers
    @sync @distributed for i in 1:Ns
        p = localpart(d)
        p[((i-1) % Int(Ns/nworkers())+1] = rand()
    end
    println(mean(d))
end