When I run this, it blocks forever and my assumption is due to the behavior of time.Tick which possibly results in a leak and the range over a channel which blocks as long as there’s a possibility of a write into the channel.
I would like to get help on clarity as to whether or not my understanding of this situation is correct.
Thank you for your response @mje
On the part of the blocking goroutine. I understand that the routine can be blocked within its own self but is this supposed to affect the main routine?
Both the main goroutine and your child goroutine are blocked waiting on reading channels that never have more data but are not closed. The child goroutine does not cause the main goroutine to block. If you want either of the goroutines to continue, you need to close their channel. The playground times out because the main goroutine is waiting for more data.
@mje That’s correct in regards to ranging over a channel but the range over the channel is expected to deadlock at a point when the runtime can no longer detect the possibility of a future write into the channel.
Say for example, this code here. It’s basically the code from above but without the go routine. Running it will deadlock as expected which makes we wonder why the other part, once added, causes the code to block forever since the main routine and goroutine are independent.
All I can guess is that the go runtime must treat blocking writing to the channel burstyLimiter <- t differently from ranging over the channel in the main goroutine with regards to deadlock detection.
@mje So, here’s my possible justification… just hoping it’s the right one.
a range over a channel will listen to incoming messages to that channel and will never stop until the runtime figures that there’s no possibility of writing into the channel in the future.
now…this means that if you have a single routine and there’s no case where the routine will write into the channel, the range will stop and run into a deadlock if the channel never received a close signal.
now, because there’s a goroutine somewhere inside the main routine, the runtime has to wait because it is unsure whether or not there will be a write into the range channel.
But why is the runtime unsure? Well…this is likely because the goroutine inside the main routine is ranging over a time.Tick which is known to be prone to resource/memory leak.
now, the other go routine that has the time.Tick is writing into a channel that’s full…that will cause a block and the routine will stay open for ever.
Now, since the main routine thinks the subroutine is still working and might be in need of the burstyRequest channel range (it’s a matter of tendency), it will never run the range into a deadlock hence, the waiting forever.
I think you’re right that this might happen because the other goroutine is still running: I rewrote your second example with an infinite for loop and it doesn’t deadlock anymore: Go Playground - The Go Programming Language
EDIT: apparently, the Go deadlock detector issues a deadlock if the number of threads created and active is higher than the number of threads waiting for work (overly simplified). This means that a “spinning” goroutine such as this one will trick the deadlock detector. I’ve found this explained in this medium post and in a stack overflow post (which I can’t link yet because I can give a max of 2 links:') )
That’s right @ozoniuss I really appreciate this articles you linked. I do hope you’ll be able to link the last one once the forum allows you the access. Really appreciate everyone’s contribution in providing clarity to the question.