
最近我在看 Go 的网络轮询器相关文章时,从源码看到 netpollinit 是通过 nonblockingPipe() 创建读写管道 来中断 epollwait ,为什么同样是 Linux 下不使用 eventfd 唤醒事件?有什么原因吗?
https://github.com/golang/go/blob/master/src/runtime/netpoll.go
func netpollinit() { epfd = epollcreate1(_EPOLL_CLOEXEC) if epfd < 0 { epfd = epollcreate(1024) if epfd < 0 { println("runtime: epollcreate failed with", -epfd) throw("runtime: netpollinit failed") } closeonexec(epfd) } r, w, errno := nonblockingPipe() if errno != 0 { println("runtime: pipe failed with", -errno) throw("runtime: pipe failed") } ev := epollevent{ events: _EPOLLIN, } *(**uintptr)(unsafe.Pointer(&ev.data)) = &netpollBreakRd errno = epollctl(epfd, _EPOLL_CTL_ADD, r, &ev) if errno != 0 { println("runtime: epollctl failed with", -errno) throw("runtime: epollctl failed") } netpollBreakRd = uintptr(r) netpollBreakWr = uintptr(w) } // netpollBreak interrupts an epollwait. func netpollBreak() { if atomic.Cas(&netpollWakeSig, 0, 1) { for { var b byte n := write(netpollBreakWr, unsafe.Pointer(&b), 1) if n == 1 { break } if n == -_EINTR { continue } if n == -_EAGAIN { return } println("runtime: netpollBreak write failed with", -n) throw("runtime: netpollBreak write failed") } } } 1 lesismal 2022 年 4 月 3 日 我不敢说这就是原因,只作为猜测: 1. pipe 和 event 都可以实现功能 2. pipe 每次只需要 write 1 字节,而 eventfd 每次必须写入大于等于 8 字节、相比之下浪费 |
2 nuk 2022 年 4 月 4 日 内核版本要求吧,不然 eventfd 应该是更好的选择 |
3 mengzhuo 2022 年 4 月 5 日 |