Go 的网络轮询器疑惑?

2022-04-03 22:06:00 +08:00
 josephxrays

最近我在看 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")
		}
	}
}

2089 次点击
所在节点    Go 编程语言
3 条回复
lesismal
2022-04-03 23:01:58 +08:00
我不敢说这就是原因,只作为猜测:
1. pipe 和 event 都可以实现功能
2. pipe 每次只需要 write 1 字节,而 eventfd 每次必须写入大于等于 8 字节、相比之下浪费
nuk
2022-04-04 01:21:48 +08:00
内核版本要求吧,不然 eventfd 应该是更好的选择
mengzhuo
2022-04-05 09:54:52 +08:00
主要考虑是 netpollBreak

https://github.com/golang/go/issues/27707

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/844792

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX