从队列中获取结果以正确发送到 socket.io

Getting results from Queue to emit to socket.io correctly

我需要在一个线程中启动一个服务器,在另一个线程中启动一个值生成器(这里由 mock_producer 模拟),服务器的后台线程应该从队列中获取每个值并将其发送到客户端。同时,WSGI 服务器应在请求时提供 index.html。这是迄今为止最好的尝试:

# pip install eventlet python-socketio

from threading import Thread
from Queue import Queue
import eventlet
import socketio

def mock_producer(queue):
    import time
    import itertools
    for count in itertools.count():
        queue.put(count)
        time.sleep(5)

def background():
    while True:
        if not queue.empty():
            value = queue.get()
            sio.emit('value', value);
        sio.sleep(0.1)

sio = socketio.Server(logger=True)
app = socketio.WSGIApp(sio, static_files={
    '/': 'index.html',
})
queue = Queue()
prod_thread = Thread(target=mock_producer, args=(queue,))
prod_thread.start()
ws_server = eventlet.listen(('', 5000))
ws_thread = sio.start_background_task(background)
eventlet.wsgi.server(ws_server, app)

附带玩具index.html:

<!doctype html>
<html>
  <head>
    <title>Test</title>
    <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.slim.js"></script>
    <script>
      const socket = io.connect();
      socket.on('value', value => console.log(value));
    </script>
  </head>
  <body></body>
</html>

让我烦恼的事情sio.sleep(0.1) 行。这显然会在将对象放入队列与将对象提供给客户端之间引入延迟(无论多么小)。但这不起作用:

def background():
    while True:
        value = queue.get()
        sio.emit('value', value);

原因是,queue.get() 块不允许 WSGI 服务器为 index.html 页面提供服务(这显然发生在同一线程上)。

当我尝试为 queue.get-emit 循环启动一个新线程时(例如使用 Thread(target=background).start() 而不是 sio.start_background_task(background)),调试输出声称 emit 正在发生,但没有任何反应正在接触客户,所以那也是失败的。

理想情况下,我希望代码在需要处理请求或队列有值之前处于空闲状态,并立即对其中任何一个做出反应。

有没有办法把它写得干干净净?

注意:不幸的是,由于关键依赖性,该项目停留在 Python 2。我相信唯一的结果是 import Queue from Queue 行,但以防万一。

Eventlet 使用协作式多任务处理。任何时候您使用标准库中的潜在阻塞函数(例如线程、同步或套接字中的函数)时,您都有阻塞整个服务器的风险。

Eventlet 提供了库中大多数阻塞函数的替代版本,因此您应该使用它们来避免此类问题。切换到 eventlet 友好函数的最简单方法是 monkey-patch the standard library.