Assume you have a long-running, “expensive” function, e.g.,
function longrun() dim = 20000 A = rand(dim,dim)/dim A^256 end
which may take a few minutes to complete, and a function that is short-running and latency-critical, e.g.,
using Dates # required to print inter-service times function heartbeat() dim = 1000 A = rand(dim, dim)/dim t = now() while (true) A^256 println("alive: $(now()-t)") t = now() end end
whose individual iterations in the while loop typically take less than a second to complete (if run separately).
I’m calling this function using
julia -t auto as follows
routines = [longrun, heartbeat] @sync for routine in routines Threads.@spawn routine() end
As I have plenty of resources, I’d naively expect the heartbeat function to print continuously, independently of the long-running function.
This is however not the case. The long-running function seems to block the heartbeat function almost entirely:
alive: 447 milliseconds
alive: 391 milliseconds
alive: 136699 milliseconds
alive: 205 milliseconds
alive: 265 milliseconds
I’m aware that this is a known problem (e.g., see How to perform ongoing background work with a real time ui - #4 by tkf), but I’m not sure how to tackle it best (without introducing dedicated processes). I’ve also tried reducing the number of BLAS threads, or using a Julia-native matrix multiplication library instead (Octavian.jl), but the issue remained.
I suspect that using two different thread pools (as introduced with 1.9) may be an option, but I fail to see how exactly.
Any suggestions would be more than welcome. I’m using Julia v1.9 on Linux.
Here’s the full code (including a failed attempt at using 1.9’s interactive feature):
using Dates function longrun() dim = 20000 A = rand(dim,dim)/dim println("starting exponentiation") A^256 println("exponentiation done") end function heartbeat() dim = 1000 A = rand(dim, dim)/dim t = now() while (true) A^256 println("alive: $(now()-t)") t = now() end end @sync begin Threads.@spawn :interactive heartbeat() Threads.@spawn longrun() end