从队列中获取结果以正确发送到 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.
我需要在一个线程中启动一个服务器,在另一个线程中启动一个值生成器(这里由 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.