The performance of the Go runtime with a million blocked goroutines is pretty OK, but its performance with even 1000 runnable goroutines is not great at all. You really need to think about which you are going to have.
I don't know which category epoll fits into, but it seems like it should be treated optimistically, since epoll is used for non-blocking I/O.
https://utcc.utoronto.ca/~cks/space/blog/programming/GoSched...
In epoll case, using RawConn.Read would look like this:
err := rawConn.Read(func(fd uintptr) bool {
nevents, err = syscall.EpollWait(int(fd), events[:], 0)
if nevents == 0 {
return false // try again
}
return true
})
Note that using RawConn.Read here is only necessary because epoll needs epoll_wait(2) instead of typical read(2). For ordinary file descriptors, like pipes, etc., setting them to non-blocking mode, wrapping them with os.NewFile, and using its ordinary Read/Write methods is sufficient.https://www.usenix.org/system/files/login/articles/chen12-06...
Go provides go routines as a building block, it's up to you to use that or use something else ( reactor pattern, epoll ect ... )