go - 是否可以在 Go 中同时等待 channel 和文件描述符?

标签 go channel

我知道我可以在 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/

相关文章:

go - 为什么goroutine中的未缓冲 channel 获得了此顺序

api - 如何使用 Telegram API 通过给定的 joinlink 获取私有(private) channel 的 chatid?

docker - docker golang主进程与python子进程通信的最佳实践

mysql - 在将 SQL 查询发送到 MySQL 之前对其进行解析

go - 使用 Go 检查 channel 是否具有准备读取的值

java - 数据报 channel 套接字不编写 Java

go - 在选择中的同一 channel 上读写

dictionary - 插入 map 时,Go(深)复制键吗?

php - 在 Go 中生成 crypt() sha512 哈希

sql - 在 Golang 中重用或复制 *sql.Rows