はじめに
Juliaは、標準ライブラリで手軽にマルチプロセスを実現することができますが、かなり初歩的な部分でハマってしまったのでメモしておきます。以下の二つのエラーに延々ハマっていました。
ERROR: LoadError: On worker 2:
ArgumentError: Package Flux [587475ba-b771-5e3f-ad9e-33799f191a9c] is required but does not seem to be installed:
- Run `Pkg.instantiate()` to install all recorded dependencies.
ERROR: LoadError: On worker 2:
UndefVarError: #func not defined
結局
-
@everywhere
はaddprocs
の後に書く - 仮想環境の場合は、
addprocs(n, exeflags="--project")
とする (公式ドキュメント)
正しく動く書き方
using Distributed
using Printf
addprocs(2, exeflags="--project") # <- project を明示
# @everywhere マクロは addproc の後に書く
@everywhere using Flux
@everywhere function veryHeavyFunc()
sleep(1)
return Flux.mae([1.1,1.9,3.1], 1:3)
end
@everywhere function veryVeryHeavyFunc()
sleep(2)
return Flux.mse([1.1,1.9,3.1], 1:3)
end
function main()
s1 = @spawnat 2 veryHeavyFunc()
s2 = @spawnat 3 veryVeryHeavyFunc()
r1 = fetch(s1)
r2 = fetch(s2)
@printf("r1 = %.5f\n", r1)
@printf("r2 = %.5f\n", r2)
end
main()
誤った書き方
下のコードは2箇所変更する必要があるので、順に解説します。
using Distributed
using Printf
@everywhere using Flux
@everywhere function veryHeavyFunc()
sleep(1)
return Flux.mae([1.1,1.9,3.1], 1:3)
end
@everywhere function veryVeryHeavyFunc()
sleep(20)
return Flux.mse([1.1,1.9,3.1], 1:3)
end
function main()
addprocs(2)
s1 = @spawnat 2 veryHeavyFunc()
s2 = @spawnat 3 veryVeryHeavyFunc()
r1 = fetch(s1)
r2 = fetch(s2)
@printf("r1 = %.5f\n", r1)
@printf("r2 = %.5f\n", r2)
end
main()
誤りその1
main_wrong.jl
using Distributed
using Printf
@everywhere using Flux
@everywhere function veryHeavyFunc()
sleep(1)
...
end
function main()
addprocs(2) # <- wrong!
s1 = @spawnat 2 veryHeavyFunc()
....
end
何も考えずに書いたら、新たなプロセスが必要となる箇所付近でプロセスを追加すると思うんですけどねー。これがまずダメでした。 addprocs
をした後に @everywhere
を付けた関数の定義および using Pacakge
を書きましょう。
main_correct.jl
using Distributed
using Printf
addprocs(2) # <- correct!
@everywhere using Flux
@everywhere function veryHeavyFunc()
sleep(1)
...
end
function main()
s1 = @spawnat 2 veryHeavyFunc()
....
end
誤りその2
これは公式ドキュメントに書いているので比較的早く気づくことができましたが、
julia --project=/path/to/env main.jl
のように仮想環境を指定して実行している場合、インストールしているパッケージを作成するプロセスでも使用したいのであれば、
addprocs(2, exeflags="--project")
のように第二引数を忘れずに記載しましょう。
別解
コマンドラインで -p 2
などとすれば、コード中に addprocs(2)
と書いた時と同じ効果が得られます。
つまり、 addprocs(2, exeflags="--project")
とはならないので、残念ながらエラーになります。
julia --project=/path/to/env -p 2 main.jl
ERROR: LoadError: On worker 2:
ArgumentError: Package Flux [587475ba-b771-5e3f-ad9e-33799f191a9c] is required but does not seem to be installed:
- Run `Pkg.instantiate()` to install all recorded dependencies.
Stacktrace:
[...]
正しく動く書き方(再掲)
using Distributed
using Printf
addprocs(2, exeflags="--project")
@everywhere using Flux
@everywhere function veryHeavyFunc()
sleep(10)
return Flux.mae([1.1,1.9,3.1], 1:3)
end
@everywhere function veryVeryHeavyFunc()
sleep(20)
return Flux.mse([1.1,1.9,3.1], 1:3)
end
function main()
s1 = @spawnat 2 veryHeavyFunc()
s2 = @spawnat 3 veryVeryHeavyFunc()
r1 = fetch(s1)
r2 = fetch(s2)
@printf("r1 = %.5f\n", r1)
@printf("r2 = %.5f\n", r2)
end
main()
まとめ
juliaの更なる発展に期待!