使用更多线程的速度比Julia中的线程慢

时间:2019-08-26 20:47:53

标签: multithreading julia

我在脚本foo.jl中具有以下代码来执行简单的可并行化任务(这看起来很平凡,但实际上与我的研究中的关键任务类似):

using LinearAlgebra
using Statistics

N = 60
length = 200

function matOps(mat1, mat2)
    mat = mat1'mat2 - mat2'mat1
    eye = Matrix{Float64}(I,N,N)
    for i in 0:10000
        mat = eye*transpose(mat)*eye
    end
    return mat
end

y = zeros(length)
println("Number of threads: $(Threads.nthreads())")
@time Threads.@threads for i in 1:length
    mat1 = rand(N,N)
    mat2 = rand(N,N)
    y[i] = mean(matOps(mat1, mat2))
end

因此,所有这些操作是对60x60矩阵执行10,000次(无意义)操作,然后取矩阵元素的均值并将其存储在长度为200的数组y中。因此我们遍历该200长数组,并为每个元素执行此矩阵操作链,并存储单个平均值。

这是非常可并行的,因为每个迭代都是完全相互独立的,但是使用更多线程运行循环实际上会更慢。下面是一些输出:

$:> julia foo.jl

Number of threads: 1
184.268869 seconds (9.85 M allocations: 107.718 GiB, 5.16% gc time)

$:> $env:JULIA_NUM_THREADS=2
$:> julia foo.jl

Number of threads: 2
377.960229 seconds (9.85 M allocations: 107.583 GiB, 71.04% gc time)

$:> $env:JULIA_NUM_THREADS=4
$:> julia foo.jl

Number of threads: 4
1121.259542 seconds (9.84 M allocations: 107.190 GiB, 94.31% gc time)

这实际上使我使用DistributedSharedArrays而不是Threads加快了速度。我也了解Threads是实验性的,因此我了解这是否正在研究中。只是以为我会检查自己是否做错了,因为仅查看时间的缩放比例,似乎每个线程都按顺序执行了整个循环。

我在Windows 10 Julia版本1.0.3上使用Powershell

编辑:我将矩阵运算从eye*mat'eye更改为eye*transpose(mat)*eye,因为它弄乱了此处的语法。由于mat是真实的,因此相同。

1 个答案:

答案 0 :(得分:0)

也许可以尝试一下(请注意,每个线程都有一个单独的RNG):

using LinearAlgebra
using Statistics
using Random 

println("Number of threads: $(Threads.nthreads())")

function matOps(mat1, mat2, N)
    mat = mat1'mat2 - mat2'mat1
    eye = Matrix{Float64}(I,N,N)
    for i in 0:10000
        mat = eye*transpose(mat)*eye
    end
    return mat
end
matOps(rand(2,2), rand(2,2), 2) # on rare occassions 
                        # multithreaded compiling fails

function get_y(N, L, rands)
    y = Vector{Float64}(undef, L)    
    Threads.@threads for i in 1:L
        mat1 = rand(@inbounds(rands[Threads.threadid()]),N,N)
        mat2 = rand(@inbounds(rands[Threads.threadid()]),N,N)
        y[i] = mean(matOps(mat1, mat2, N))
    end
    y
end

const N = 60
const L = 20

const rands = [MersenneTwister(i) for i in 1:Threads.nthreads()]
@time get_y(N, L, rands);
@time get_y(N, L, rands);

一个线程:

> julia foo.jl
Number of threads: 1
 15.137731 seconds (958.56 k allocations: 10.771 GiB, 9.40% gc time)
 12.788418 seconds (800.34 k allocations: 10.763 GiB, 7.24% gc time)

两个线程:

> julia foo.jl
Number of threads: 2
  8.573475 seconds (958.52 k allocations: 10.767 GiB, 14.13% gc time)
  7.947657 seconds (800.25 k allocations: 10.756 GiB, 12.73% gc time)