5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

複数台のラズパイを使って Distributed.jl で分散計算をさせる(その二)

Last updated at Posted at 2025-12-09

本日は

アドベントカレンダー $N=10$ 日目です.

複数台のラズパイを使って Distributed.jl で分散計算をさせる(その二)です.

下記の記事の続きです

前回はシンプルな和をとる計算で計算させましたが,今回はマンデルブロ集合を計算しましょう.この計算は広い領域を複数の領域に分割し,分割した領域に対してラズパイが計算を担当するというものでやや高度なものになります.この場合は Distributed.jl だけではなく配列のやり取りも含むので DistributedArrays.jl を使うことになります.

前提

  • ラズパイなど複数の計算マシンを持っている
  • 作業マシンに Julia が入っており,いくつかのパッケージを導入できる権限を持っていること
  • 作業マシンと計算マシンの間でSSH 接続ができること

計算マシンで行うこと

  • Julia を事前にインストールしておく
  • 下記の三つのパッケージを入れておく
pkg> add DistributedArrays OffsetArrays ImageCore Sixel

作業マシンで行うこと.

  • Julia を事前にインストールしておく
  • 下記の三つのパッケージを入れておく
pkg> add DistributedArrays OffsetArrays ImageCore Sixel
  • 各々の計算マシンに対して SSH 接続ができることを確認

計算スクリプトの用意

次のようなスクリプトを用意しておきます.

mandelbrot.jl
using Distributed

if nworkers() == 1
    @info "Start machines..."
    p = addprocs(
        [
            ("terasaki@rpi5-1.local", 1),
            ("terasaki@rpi5-2.local", 1),
            ("terasaki@rpi5-3.local", 1),
            ("terasaki@rpi5-4.local", 1),
            ("terasaki@rpi5-5.local", 1),
            ("terasaki@rpi5-6.local", 1),
            ("terasaki@rpi5-7.local", 1),
            ("terasaki@rpi5-8.local", 1),
        ],
        dir = "/home/terasaki",
        exename = "/home/terasaki/.juliaup/bin/julia",
        exeflags = "--threads=4",
    )

    @info "Machines launched!"
end

@info "Running @everywhere macro"
@everywhere begin
    using DistributedArrays, OffsetArrays

    Base.@kwdef struct Param{I,F}
        xmin::F = -1.75
        xmax::F = 0.75
        width::I = 4096
        #width::I = 256
        ymin::F = -1.25
        ymax::F = 1.25
        height::I = 4096
        #height::I = 256
        max_iter::I = 500
    end

    function mandelbrot_kernel(param::Param, c)
        (; max_iter) = param
        z = c
        for i = 0:max_iter-1
            z = z * z + c
            abs(z) > 2 && return i
        end
        max_iter
    end

end # everywhere

function makeaxes(param::Param)
    (; xmin, xmax, width, ymin, ymax, height) = param
    x = range(xmin, xmax, width + 1)[begin:end-1]
    y = range(ymin, ymax, height + 1)[begin:end-1]
    x, y
end

function makeinput(param::Param)
    x, y = makeaxes(param)
    complex.(x, y')
end

function distributed_compute_mandelbrot(param::Param, input)
    e = @elapsed Data = distribute(input)
    @info "distribute" e
    e = @elapsed Result = DArray(size(Data)) do inds # local indices on each processor
        arr = zeros(inds) # We create an OffsetArray with the correct local indices
        data_local = OffsetArray(localpart(Data), localindices(Data)) # get the local part of data on each processor and assign the proper indices
        Base.Threads.@threads for i in eachindex(data_local)
            c = data_local[i]
            arr[i] = mandelbrot_kernel(param, c)
        end
        parent(arr) # strip the OffsetArray wrapper
    end
    @info "Calculation" e
    return Result
end

using ImageCore
using Sixel

@info "Setup done"
@info "We have $(nworkers()) workers"

function main()
    param = Param()
    inputz = makeinput(param)
    @time doutput = distributed_compute_mandelbrot(param, inputz)
    e = @elapsed output = Matrix(doutput) # gather data in each processor and collect to host machie
    @info "Gather data " e
    @assert maximum(output) > 0
    normalized = output / maximum(output)
    gray = colorview(Gray, normalized')
    sixel_encode(gray)
end

@info "Run main() manually"

if abspath(PROGRAM_FILE) == @__FILE__
    main()
end

作業マシンで include("mandelbrot.jl") を実行します.

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.12.2 (2025-11-20)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org release
|__/                   |

julia> include("mandelbrot.jl")
[ Info: Start machines...
[ Info: Machines launched!
[ Info: Running @everywhere macro
[ Info: Setup done
[ Info: We have 8 workers
[ Info: Run main() manually

main() を実行します.

ラズパイ側で計算が実行されていることが確認できます.領域によって計算がすぐに終わるのでCPUの負荷は担当する領域によってまちまちになります.

Screenshot 2025-12-06 at 19.57.36.png

iTerm2 上で実行すると下記のように画像データを表示することができます.多分計算ができてるでしょう.

データの分配の 6 秒,計算に 15 秒, 集約に 5 秒かかってることになります.総計で概ね 21 秒かかっています.

Screenshot 2025-12-06 at 19.59.27.png


手元のマシン (M2 Max 12 core) で行うと下記のようになりました.

julia> main()
┌ Info: distribute
└   e = 1.026301666
┌ Info: Calculation
└   e = 4.5218025
  5.554594 seconds (2.77 M allocations: 395.196 MiB, 0.23% gc time, 11.88% compilation time)
┌ Info: Gather data
└   e = 0.476176084

前回はラズパイクラスタが勝ちましたが,今回のタスクだと手元のマシンが勝ちましたね.

まとめ

DistributedArrays.jl を使う分散計算の例を紹介しました.
あまり例がなかったのでお役に立てれば幸いです.

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?