我遇到了这样一种情况:我从客户端接收到消息。在处理该请求的函数 (@socketio.on) 中,我想调用一个执行某些重型工作的函数。这不应该导致主线程被阻塞,而且应该在工作完成后通知客户端。因此我启动了一个新线程。
现在我遇到了一个非常奇怪的行为:
消息永远不会到达客户端。然而,代码却到达了发送消息的那个特定点。
更令人惊讶的是,如果线程中除了向客户端发送消息之外没有其他活动,则答复实际上会传递到客户端。
总之:
如果在发送消息之前发生了计算密集型操作,则消息将无法传递,否则可以传递。
就像这里和这里所说的那样,从线程发送消息到客户端根本不是问题:
在目前为止显示的所有示例中,服务器都会响应客户端发送的事件。但对于某些应用程序,服务器需要是消息的发起者。这可以将服务器中发生的事件通知客户端,例如在后台线程中。
以下是示例代码。当删除注释符号(#)时,消息('foo from thread')不会传递到客户端,否则会传递。
from flask import Flask
from flask.ext.socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app)
from threading import Thread
import time
@socketio.on('client command')
def response(data):
thread = Thread(target = testThreadFunction)
thread.daemon = True
thread.start()
emit('client response', ['foo'])
def testThreadFunction():
# time.sleep(1)
socketio.emit('client response', ['foo from thread'])
socketio.run(app)
我正在使用Python 3.4.3,Flask 0.10.1,flask-socketio1.2和eventlet 0.17.4。
这个示例可以复制并粘贴到.py文件中,行为可以立即重现。
有人能解释一下这种奇怪的行为吗?
更新
看起来这是eventlet的一个bug。如果我执行:
socketio = SocketIO(app, async_mode='threading')
即使已经安装,它也会强制应用程序不使用eventlet。
然而,对我来说,这不是可行的解决方案,因为使用'threading'作为async_mode会拒绝接受二进制数据。每次我从客户端发送一些二进制数据到服务器时,它会显示:
WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved performance.
第三个选项,使用gevent作为async_mode对我也不起作用,因为gevent还不支持python 3。
还有其他建议吗?