Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 27 additions & 23 deletions docs/src/tutorials/algorithms/parallelism.jl
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,16 @@ 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 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)
Expand All @@ -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)
Expand Down
Loading