Closed lehins closed 5 years ago
Yes, this is a known limitation in GHC's concurrency implementation. The workaround is to use -fno-omit-yields
.
@simonmar So, is this because normally there is a preemptive timer that is supposed to introduce yielding in non-allocating, non-I/O-doing threads? But -fomit-yields
turns that off by default? Is that an efficiency trade-off?
Not quite - GHC's concurrency implementation is quasi-cooperative, that is, threads must voluntarily yield to the scheduler. The voluntary nature is normally invisible to the programmer because it happens at every heap allocation, and those normally happen often enough for it to look like preemption. But if you happen to write a loop that runs for a long time without allocating any memory, it won't be preempted at all - indeed the GC won't be able to run, and all the other threads in the system will be blocked (even when using +RTS -N
). The -fno-omit-yields
flag inserts yield points in enough places that this can't happen, at the expense of some performance.
One thing we haven't done is try to optimise -fno-omit-yields
to reduce the overhead, that would be a nice project for someone.
@simonmar Thanks for the explanation!
This simple code results in a deadlock. Solution is to stick a
yield
inside theotherwise
clause of thecheck
function, but that's not always possible, since check can be pure function with a loop in it.Here is a repo that can be used to reproduce the issue: https://github.com/lehins/async-bug-repro running
stack run
should result in a deadlock