我知道我可以在 Go 中使用 select {}
语法等待多个 channel ,并使用 syscall.Select()
或类似函数等待多个文件描述符。但是是否可以同时在两个 channel 上等待?
作为背景,我希望有一个 goroutine 通过 channel 接受消息并通过套接字连接(由 gozmq 提供)转发它们,同时等待套接字连接的回复。
由于底层库的线程安全要求,一次只能在一个线程中访问套接字,这就是为什么我想知道是否有一种方法可以从单个 goroutine 处理这个问题。
最佳答案
无法同时选择 channel 和文件描述符,因为抽象处于不同的级别。 channel 由 go 运行时处理,文件描述符由操作系统处理。您需要在它们之间架起一座桥梁,这可以通过 net.Pipe()
来完成。
你需要做的就是将一个 goroutine 专用于 epoll()
/select()
来观察你的 zmq-sockets 和一个单一的“唤醒”net.Pipe()
。这是您的投票服务器。另一个 goroutine 监听你的读写 channel 。当有人在读或写 channel 上发送时,第二个 goroutine 将在管道上发送以唤醒轮询服务器。
这就是标准库中的 net 包的工作方式。我强烈建议阅读它以获得灵感(或窃取...... BSD 许可证非常自由)。
这里是网络本身对 pollServer 的描述。您可能需要阅读代码才能理解其中的含义,但是 fd.go
中的这一部分应该是一个很好的起点。
// A pollServer helps FDs determine when to retry a non-blocking
// read or write after they get EAGAIN. When an FD needs to wait,
// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
// request to the poll server. Then receive on fd.cr/fd.cw.
// When the pollServer finds that i/o on FD should be possible
// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
// This protocol is implemented as s.WaitRead() and s.WaitWrite().
//
// There is one subtlety: when sending on s.cr/s.cw, the
// poll server is probably in a system call, waiting for an fd
// to become ready. It's not looking at the request channels.
// To resolve this, the poll server waits not just on the FDs it has
// been given but also its own pipe. After sending on the
// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
// byte to the pipe, causing the pollServer's poll system call to
// return. In response to the pipe being readable, the pollServer
// re-polls its request channels.
//
// Note that the ordering is "send request" and then "wake up server".
// If the operations were reversed, there would be a race: the poll
// server might wake up and look at the request channel, see that it
// was empty, and go back to sleep, all before the requester managed
// to send the request. Because the send must complete before the wakeup,
// the request channel must be buffered. A buffer of size 1 is sufficient
// for any request load. If many processes are trying to submit requests,
// one will succeed, the pollServer will read the request, and then the
// channel will be empty for the next process's request. A larger buffer
// might help batch requests.
//
// To avoid races in closing, all fd operations are locked and
// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
// and sets a closing flag. Only when the last reference is removed
// will the fd be closed.
祝你好运重新实现网络。最后的好消息是,您的 zmq-socket 在 go 中将是线程安全的。
关于go - 是否可以在 Go 中同时等待 channel 和文件描述符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11342833/