Multi-Threading

Start Julia with threads: julia -t auto (or JULIA_NUM_THREADS).

Start Julia with threads: julia -t auto (or JULIA_NUM_THREADS).

Threads.nthreads(), Threads.threadid()

# Parallel loop
results = zeros(100)
Threads.@threads for i in 1:100
    results[i] = expensive(i)              # each iteration writes its own slot: safe
end

# Task-based parallelism (composable, dynamic scheduling)
function psum(v)
    chunks = Iterators.partition(v, length(v) ÷ Threads.nthreads())
    tasks = [Threads.@spawn sum(c) for c in chunks]
    sum(fetch.(tasks))
end

# Parallel recursive fib
function pfib(n)
    n < 25 && return fib(n)
    t = Threads.@spawn pfib(n - 1)
    return pfib(n - 2) + fetch(t)
end

28.1 Avoiding data races

Don't index per-thread buffers with threadid() (tasks can migrate); allocate per-task state instead.

total = Threads.Atomic{Int}(0)
Threads.@threads for i in 1:1000
    Threads.atomic_add!(total, i)
end
total[]

lk = ReentrantLock()
acc = Float64[]
Threads.@threads for i in 1:10
    v = i^2
    lock(lk) do
        push!(acc, v)                       # push! on a shared array needs a lock
    end
end

mutable struct Counter; @atomic n::Int; end   # atomic fields (1.7+)

28.2 Higher-level threading packages

OhMyThreads.jl (tmap, tforeach, treduce), ThreadsX.jl (parallel sum, map, sort), FLoops.jl / Folds.jl (transducer-based), Polyester.jl (@batch, low overhead). Also multithreaded BLAS (BLAS.set_num_threads).