我们有一个基于 asyncore 的网络客户端,用户的网络连接体现在一个Dispatcher
. 目标是让从交互式终端工作的用户能够输入网络请求命令,这些命令将发送到服务器并最终返回答案。客户端被编写为异步的,因此用户可以同时在不同的服务器上启动多个请求,并在结果可用时收集它们。
当我们在一个选择循环中进行时,我们如何允许用户输入命令?如果我们点击select()
只注册为可读的调用,那么我们将坐在那里直到我们读取数据或超时。在此(可能很长)时间内,用户输入将被忽略。如果我们总是注册为可写的,我们会得到一个热循环。
一种不好的解决方案如下。我们在自己的线程中运行选择循环,并通过调用我们在 Dispatcher 上定义的方法让用户将输入注入到线程安全的写入队列中。就像是
def myConnection.enqueue(self, someData):
self.lock.acquire()
self.queue.put(someData)
self.lock.release()
然后,我们仅在队列不是 emtpy 时才注册为可写
def writable(self):
return not self.queue.is_empty()
然后,我们将指定一个超时,因为select()
它在人类尺度上很短,但对计算机来说很长。这样,如果我们在select
用户输入新数据时只注册用于读取的调用,循环最终将再次运行并发现有新数据要写入。这是一个糟糕的解决方案,因为我们可能也希望将此代码用于服务器的客户端连接,在这种情况下,我们不希望您等待的死区select()
时间超时。再次,我意识到这是一个糟糕的解决方案。
似乎正确的解决方案是通过文件描述符引入用户输入,以便我们可以在select
仅注册为可读的调用中检测新输入。有没有办法做到这一点?
注意:这是为了简化此处发布的问题