This is in the process of changing; it used to be that the inner nested @threads would only schedule work on threads if on thread 1 (that’s version 1.4). The outer loop splits into two threads — and only one of those two will see multithreading inside it. So the “three threads” portion is simply the straggling 2 elements from the inner for loop on that first iteration. This is changing in 1.5 and will likely change again to fully participate in the depth-first queue. Version 1.5:
julia> @show Threads.nthreads()
Threads.nthreads() = 8
8
julia> t0 = now()
2020-05-29T10:28:55.45
julia> tmap(1:2) do i
tmap(10:10:100) do j
stamp(i,j)
sleep(1)
end
end
167 milliseconds (2, 10)
167 milliseconds (1, 10)
1202 milliseconds (1, 20)
1202 milliseconds (2, 20)
2206 milliseconds (2, 30)
2206 milliseconds (1, 30)
3209 milliseconds (1, 40)
3209 milliseconds (2, 40)
4210 milliseconds (2, 50)
4210 milliseconds (1, 50)
5217 milliseconds (1, 60)
5217 milliseconds (2, 60)
6220 milliseconds (2, 70)
6220 milliseconds (1, 70)
7222 milliseconds (2, 80)
7222 milliseconds (1, 80)
8225 milliseconds (1, 90)
8225 milliseconds (2, 90)
9230 milliseconds (2, 100)
9230 milliseconds (1, 100)
https://docs.julialang.org/en/v1.6-dev/base/multi-threading/#Base.Threads.@threads