Ниже приведены две версии одного и того же кода - однопотоковая и многопоточная, генерирующая DataFrame
из набора DataFrame
s, возвращаемых функцией f()
и имеющих случайную длину.
using Random
using DataFrames
using BenchmarkTools
function f(rngs::Vector{Random.MersenneTwister}, offset)::DataFrame
t = Threads.threadid()
n = rand(rngs[t+offset], 1:20)
DataFrame(a=1:n,b=21:(20+n),t=t+offset)
end
function test_threads(rngs::Vector{Random.MersenneTwister})
res = DataFrame([Int,Int,Int],[:a,:b,:t],0)
lock = Threads.SpinLock()
Threads.@threads for i in 1:100
df = f(rngs,0)
Threads.lock(lock)
append!(res,df)
Threads.unlock(lock)
end
res
end
function test_normal(rngs::Vector{Random.MersenneTwister})
res = DataFrame([Int,Int,Int],[:a,:b,:t],0)
for i in 1:100
append!(res,f(rngs, i%2))
end
res
end
Теперь давайте проведем тестирование:
julia> rngs = [Random.MersenneTwister(i) for i in 1:2];
julia> @btime test_normal($rngs);
891.306 μs (5983 allocations: 476.67 KiB)
rngs = [Random.MersenneTwister(i) for i in 1:Threads.nthreads()];
@btime test_threads($rngs);
674.559 μs (5549 allocations: 425.69 KiB)