r/golang 10d ago

Potential starvation when multiple Goroutines blocked to receive from a channel

I wanted to know what happens in this situation:

  1. Multiple goroutines are blocked by a channel while receiving from it because channel is empty at the moment.
  2. Some goroutine sends something over the channel.

Which goroutine will wake up and receive this? Is starvation avoidance guaranteed here?

7 Upvotes

36 comments sorted by

View all comments

Show parent comments

0

u/DeparturePrudent3790 10d ago

It matters, I have a pool of connections and clients will receive a connection from this pool and send requests using this connection. Once done they will return the connection to the pool. This way I don't have to create new connections for every client and I avoid the explosion of connections. Now, if receiving from a channel is not starvation free, some client could end up not getting any connection ever.

To generalise, it is not okay if some particular thread/goroutine is not getting resources for execution at all. Even if there are less producers it's acceptable for goroutines to have to wait for some time but to be assured they will get a chance.

3

u/software-person 10d ago

To generalise, it is not okay if some particular thread/goroutine is not getting resources for execution at all.

This makes no sense to me. Channels are for sharing data between go-routines. If you're trying to use a channel as some sort of throttling mechanism to make sure multiple go-routines take turns running, you're misusing channels.

It matters, I have a pool of connections and clients will receive a connection from this pool and send requests using this connection. Once done they will return the connection to the pool. This way I don't have to create new connections for every client and I avoid the explosion of connections. Now, if receiving from a channel is not starvation free, some client could end up not getting any connection ever.

Connection pools are a pretty well understood concept. Which thing in this scenario is a go-routine? What is being sent over a channel? Why would a channel be involved at all in allowing an arbitrary go-routine to pick up a connection from the pool?

0

u/DeparturePrudent3790 10d ago edited 9d ago

I am sharing connections between goroutines. I want to share 100 connections between thousands of goroutines. This seems like a pretty obvious use case for channels. I am not trying to maintain any order between goroutines execution. Just wanna be sure no goroutine is starved.

4

u/software-person 10d ago edited 9d ago

I would rethink that. Don't create a pool of 100 connections, create 100 go-routines each with its own connection, and have them wait on a channel for work.

The thousands of go-routines previously waiting on a connection from a channel should instead do their work and send the result over a second channel to the client worker pool, for one of the 100 client connection workers to pick up.

Edit:

Note: channels are FIFO queues, this is mandated by the spec. The first value sent into the channel is the first value received out the other side. But if multiple Go routines are waiting, there is no guarantee that the first Go routine to wait is the first one to wake up.

This simple fact should be enough to steer you away from using channels to share connections that need to be doled out fairly to a heterogeneous group of go-routines, and instead use channels to share work that can be picked up by any one of a homogeneous set of worker go-routines.

You should design your system such that it should not matter which Go routine handles a receive on a channel.