Параллельные операции над массивами в Юлии - PullRequest
1 голос
/ 25 октября 2019

Что такое параллельная (для нескольких процессоров) версия этого кода в Julia?

V = zeros(3)
for i = 1:100000
    cc = rand(1:3)
    V[cc] += 1
end

1 Ответ

2 голосов
/ 25 октября 2019

Это прямая перезапись вашего цикла, которая поддерживает потоки и предотвращает ложное совместное использование:

using Random
using Base.Threads

V = let
    mt = Tuple([MersenneTwister() for _ in 1:nthreads()])
    Vv = Tuple([zeros(3) for _ in 1:nthreads()])
    @threads for i = 1:100000
        @inbounds cc = rand(mt[threadid()], 1:3)
        @inbounds Vv[threadid()][cc] += 1
    end
    reduce(+, Vv)
end

Тем не менее, в общем случае для такой небольшой работы, вероятно, использование потоков не принесет вам большой пользы. ,Кроме того, если вам действительно нужна производительность, возможно, код должен быть немного реструктурирован, например, так:

function worker(iters, rng)
    v = zeros(3)
    for i = 1:iters
        cc = rand(rng, 1:3)
        v[cc] += 1
    end
    v
end

V = let
    mt = Tuple([MersenneTwister() for _ in 1:nthreads()])
    Vv = [zeros(3) for _ in 1:nthreads()]
    jobs_per_thread = fill(div(100000, nthreads()),nthreads())
    for i in 1:100000-sum(jobs_per_thread)
        jobs_per_thread[i] += 1
    end
    @assert sum(jobs_per_thread) == 100000
    @threads for i = 1:nthreads()
        Vv[threadid()] = worker(jobs_per_thread[threadid()], mt[threadid()])
    end
    reduce(+, Vv)
end

Также в Julia 1.3 вам не придется выполнять ручное MersenneTwister управление, так как Julia создаст отдельный PRNG длянить.

...