2016-01-03 8 views
15

Я в ситуации, когда получаю сообщение от клиента. Внутри функции, которая обрабатывает этот запрос (@ socketio.on), я хочу вызвать функцию, где выполняется какая-то тяжелая работа. Это не должно приводить к блокировке основного потока, и считается, что клиент будет проинформирован после завершения работы. Таким образом, я начинаю новый поток.Python - Flask-SocketIO отправить сообщение из потока: не всегда работает

Теперь я сталкиваюсь с действительно странным поведением: Сообщение никогда не доходит до клиента. Однако код достигает этого места, где отправляется сообщение. Еще более удивительным является тот факт, что если в потоке ничего не происходит, кроме сообщения, отправляемого клиенту, то ответ на самом деле находит свой путь к клиенту.

Подводя итог: Если что-то вычислительно интенсивно происходит до отправки сообщения, оно не доставляется, иначе это так.

Как сказано here и here, отправка сообщений из потока для клиентов это не проблема вообще:

Во всех примерах не показано до этого момента сервер реагирует на события, посылаемые клиент. Но для некоторых приложений сервер должен быть инициатором сообщения. Это может быть полезно для отправки уведомлений клиентам о событиях, возникших на сервере, например, в фоновом потоке.

Вот пример кода. При удалении комментариев (*) сообщение («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, 0.10.1 Колба, склянки-socketio1.2, eventlet 0.17.4.

Этот образец может быть скопирован и вставлен в .py-файл, и поведение может быть немедленно воспроизведено.

Может ли кто-нибудь объяснить это странное поведение?

Update

Это кажется ошибка в eventlet. Если я это сделаю:

socketio = SocketIO(app, async_mode='threading') 

Это заставляет приложение не использовать флажок, хотя он установлен.

Однако это не применимое решение для меня, как использование «threading», поскольку async_mode отказывается принимать двоичные данные. Каждый раз, когда я отправляю некоторые двоичные данные от клиента к серверу он говорит:

WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved performance.

Третий вариант, используя GEvent как async_mode не работает для меня, а также GEvent не имеет поддержки для Python 3 все же.

Значит, любые другие предложения?

+0

@rfkortekaas, как это делает смысл в асинхронном протоколе? И кроме того, ответ отправляется. Это то, что «испускает». Другое дело происходит в отдельном потоке. – Schnodderbalken

+0

Я удалил свой комментарий, поскольку я неправильно понял вопрос. – rfkortekaas

+0

Я столкнулся с очень похожими проблемами, но мы ничего не делали с вычислительной дороговизной. Кажется, проблема связана с захватом надлежащего «сокета» при вызове socketio.emit. Потому что emit DOES происходит, но клиенты не получают сообщение. Добавление async_mode = 'threading', похоже, устранило проблему. Но, надеюсь, есть лучший способ. – AMB0027

ответ