-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
It would be nice to have a non-blocking take! to pull work from a Channel without hanging.
My particular use case is for a program with small units of work that can't be grouped into larger sets because each iteration relies on the results of the last. With so little to do for each unit of work, spawning a task for every one is a lot of overhead, so I would like to use long-lived tasks that repeatedly pull work from a shared queue until the simulation is finished. Here's some pseudocode demonstrating the concept:
# Create a workqueue
workqueue = Channel{Blah}(blah)
# Spawn worker threads that repeatedly pull work from the queue
for _ in 2:Threads.nthreads()
Threads.@spawn while true
try
work = take!(workqueue)
dowork(work)
catch e
e isa InvalidStateException && e.state === :closed && break
rethrow(e)
end
end
end
# Actual work loop
while whatever
# Put work into the queue
for i in something
put!(i, workqueue)
end
# Do main thread stuff
dosomethingwhilewaiting()
# If there's still work, help out
while workremains # using an atomic int as a counter, for example
work = nonblockingtake!(workqueue) # <<< THE CALL
work !== None && dowork(work)
end
end
# Tell worker threads we're done
close(workqueue)For this particular case, the body of the loop in which the main thread takes work from the queue could conceptually be replaced by yield(), but that doesn't seem to perform well from what I've seen. Even if yield() could work in that case, though, I have to imagine there are other cases where not having a non-blocking take! makes life harder.