Threads.@threads scheduling puzzle

Consider this

function test(duration)
  Threads.@threads for i=1:length(duration)
    sleep(duration[i])
  end
end

In my 2 core computer, 4 total threads with hyperthreading, running the above with

julia> @time test([2 1 1 1 2])
  3.005311 seconds (47 allocations: 2.625 KiB)

indicates that either the two sleep(2) are executed in the same “batch” or that, a thread that finished its sleep(1), starts immediately a sleep(2) call.

However

julia> @time test([2 1 1 1 1])
  3.006186 seconds (47 allocations: 2.625 KiB)

contradicts the above. How are the loop iterations scheduled to the worker threads?

I use Julia Version 1.7.0 (2021-11-30) with macOS 11.6.1 on a Dual-Core Intel Core i5.

I’ll copy the help from @threads since it is useful here:

help?> Threads.@threads
  Threads.@threads [schedule] for ... end

  A macro to parallelize a for loop to run with multiple threads. Splits the iteration space among multiple tasks and runs those
  tasks on threads according to a scheduling policy. A barrier is placed at the end of the loop which waits for all tasks to finish
  execution.

  The schedule argument can be used to request a particular scheduling policy. The only currently supported value is :static, which
  creates one task per thread and divides the iterations equally among them. Specifying :static is an error if used from inside
  another @threads loop or from a thread other than 1.

  The default schedule (used when no schedule argument is present) is subject to change.

So it is divided statically which each thread gets a chunk of the input array.

Thank you for replying!

So among the four threads, the first thread is statically assigned loop iterations 1 and 2, and the rest of threads take one loop iteration each.

julia> @time test([2 1 1 1 1])
  3.010163 seconds (48 allocations: 2.922 KiB)

julia> @time test([1 2 1 1 1])
  3.007890 seconds (47 allocations: 2.625 KiB)

julia> @time test([1 1 2 1 1])
  2.017557 seconds (47 allocations: 2.625 KiB)

julia> @time test([1 1 1 2 1])
  2.005200 seconds (47 allocations: 2.625 KiB)

julia> @time test([1 1 1 1 2])
  2.017319 seconds (47 allocations: 2.625 KiB)

julia> @time test([1 1 2 2 2])
  2.012130 seconds (47 allocations: 2.625 KiB)