This makes a lot of sense, go-blocks can get away with sharing a single thread pool because the assumption is that most of their time is spent being “parked”, but this means you have to be pretty careful about what you do inside go-blocks, something that people might only realize after a lot of their async code has already been written.
This blog post from 2013 by Martin Trojer explains in more depth what exactly the issue is.
<!! in the calling context of a go-block is straightforward advice, but what about other types of blocking calls? In principle any kind of IO should be avoided, including HTTP requests (unless they’re async), derefing a future, or even a simple
println (if the process attached to standard out can’t keep up then all your go-blocks will grind to a halt.) You could also argue that computationally intensive work inside go-blocks should be avoided.
In general it seems there’s not much awareness about this, and I’m wondering how people deal with this in practice. Where do you draw the line? Do you look out for this in code reviews? Any particular patterns that you’ve found useful?
At Nextjournal we created a wrapper namespace that performs some extra checks, and this certainly caught some cases that we otherwise wouldn’t have spotted. We’re looking for go-blocks that don’t contain
alts!, and for calls to the blocking equivalents inside a go-block’s dynamic scope.
Does this hold water or is it a bad idea? What downsides can you see in this approach.