From ab90af42a1d9c8ae74a897dc56925e591a285039 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 21 May 2026 10:20:58 +1200 Subject: [PATCH 1/2] [docs] change the parallelism tutorial to spawn only a limited set of tasks --- docs/src/tutorials/algorithms/parallelism.jl | 48 +++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/docs/src/tutorials/algorithms/parallelism.jl b/docs/src/tutorials/algorithms/parallelism.jl index e6e9346a432..9f6432bc7ee 100644 --- a/docs/src/tutorials/algorithms/parallelism.jl +++ b/docs/src/tutorials/algorithms/parallelism.jl @@ -359,11 +359,14 @@ a_correct_way_to_build_with_multithreading() # ## Example: using Channels -# Here's an example where we split the model building from the model solution. -# Instead of using an explicit `ReentrantLock`, we use a `Channel` to store the -# solutions. +# Here's an example where, instead of using an explicit `ReentrantLock`, we use +# `Channel`s to communicate between threads. -function build_model(s::Int; N::Int = 80) +struct Solution + scenario::Int + objective_value::Float64 +end +function runner(in_ch::Channel{Int}, out_ch::Channel{Solution}; N::Int = 80) model = Model(HiGHS.Optimizer) set_silent(model) @variable(model, x[1:N], Bin) @@ -373,32 +376,33 @@ function build_model(s::Int; N::Int = 80) @constraint(model, [i in 1:N, j in 1:N], z[i, j] <= y[j]) @constraint(model, [i in 1:N, j in 1:N], z[i, j] >= x[i] + y[j] - 1) @objective(model, Min, sum(rand(-10:10) * i for i in z)) - set_time_limit_sec(model, s) - return model -end -struct Solution - scenario::Int - objective_value::Float64 -end -function solve_model(ch::Channel{Solution}, s::Int, model::Model) - optimize!(model) - @assert has_values(model) # There is always the trivial solution - put!(ch, Solution(s, objective_value(model))) + while true + s = take!(in_ch) + set_time_limit_sec(model, s) + optimize!(model) + @assert has_values(model) # There is always the trivial solution + put!(out_ch, Solution(s, objective_value(model))) + end return end function run_channel_example(S::Int) - models = Vector{Model}(undef, S) - Threads.@threads for s in 1:S - models[s] = build_model(s) + tasks, solutions = Channel{Int}(S), Channel{Solution}(S) + ## Start by filling up the set of tasks + for s in 1:S + put!(tasks, s) end - ch = Channel{Solution}() - for (s, model) in enumerate(models) - Threads.@spawn solve_model(ch, s, model) + ## Now start the worker threads. Hopefully nthreads() << S. You should, in + ## general, not `@spawn` more tasks than there are threads. + for _ in 1:Threads.nthreads() + Threads.@spawn runner(tasks, solutions) end + ## Now we can consume the solutions: for i in 1:S - solution = take!(ch) + solution = take!(solutions) println("s=$(solution) [solved $i/$S]") end + ## Finally, close the `tasks` channel. + close(tasks) return end run_channel_example(15) From 0e6c144d18c8527a218283e24939d607d204e564 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 21 May 2026 11:39:50 +1200 Subject: [PATCH 2/2] Apply suggestion from @odow --- docs/src/tutorials/algorithms/parallelism.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/algorithms/parallelism.jl b/docs/src/tutorials/algorithms/parallelism.jl index 9f6432bc7ee..cbf41183c53 100644 --- a/docs/src/tutorials/algorithms/parallelism.jl +++ b/docs/src/tutorials/algorithms/parallelism.jl @@ -357,7 +357,7 @@ a_correct_way_to_build_with_multithreading() # for help on the [community forum](https://jump.dev/forum). Make sure to # include a reproducible example of your code. -# ## Example: using Channels +# ### Example: using Channels # Here's an example where, instead of using an explicit `ReentrantLock`, we use # `Channel`s to communicate between threads.