2016-01-03 66 views
15

Jestem w sytuacji, gdy otrzymuję wiadomość od klienta. W funkcji, która obsługuje to żądanie (@ socketio.on), chcę wywołać funkcję, w której wykonuje się ciężką pracę. Nie powinno to powodować blokowania głównego wątku, a klient jest uważany za poinformowanego po zakończeniu pracy. W ten sposób zaczynam nowy wątek.Python - Flask-SocketIO wyślij wiadomość z wątku: nie zawsze działa

Teraz pojawia się naprawdę dziwne zachowanie: Wiadomość nigdy nie dociera do klienta. Jednak kod dociera do tego konkretnego miejsca, w którym wysyłana jest wiadomość. Jeszcze bardziej zaskakujące jest to, że jeśli nic się nie dzieje w nici, z wyjątkiem wiadomości wysyłanej do klienta, odpowiedź trafia do klienta.

Podsumowując: Jeśli wydarzy się coś obciążającego obliczenia przed wysłaniem wiadomości, nie jest ona dostarczana, w przeciwnym razie jest.

Jak to powiedział here i here, wysyłanie wiadomości z wątku do klientów nie jest w ogóle problem:

We wszystkich przykładach pokazano tego momentu serwer odpowiada na zdarzenia wysłanego przez klient. Jednak w przypadku niektórych aplikacji serwer musi być twórcą wiadomości. Może to być przydatne do wysyłania powiadomień do klientów zdarzeń, które pochodzą z serwera, na przykład w wątku tła.

Oto przykładowy kod. Podczas usuwania komentarza (#) wiadomość ("foo z wątku") nie trafia do klienta, w przeciwnym razie jest.

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) 

Używam Python 3.4.3, kolba 0.10.1, kolba-socketio1.2, eventlet 0.17.4.

Ta próbka może zostać skopiowana i wklejona do pliku .py, a zachowanie można natychmiast odtworzyć.

Czy ktoś może wyjaśnić to dziwne zachowanie?

Aktualizacja

Wydaje się być bug eventlet. Jeśli to zrobię:

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

Wymusza to, że aplikacja nie będzie używać zdarzenia, mimo że jest zainstalowana.

Jednak nie jest to odpowiednie rozwiązanie dla mnie, ponieważ używa "wątków", ponieważ async_mode odmawia akceptacji danych binarnych. Za każdym razem, kiedy wysłać jakieś dane binarne od klienta do serwera, to mówi:

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

Trzecia opcja, za pomocą gevent jako async_mode nie działa na mnie jak gevent nie posiada wsparcia dla Pythona 3 jeszcze.

Jakieś inne sugestie?

+0

@rfkortekaas jaki to ma sens w asynchronicznym protokołem? Poza tym odpowiedź jest wysyłana. Tak właśnie działa "emitowanie". Inna rzecz dzieje się w osobnym wątku. – Schnodderbalken

+0

Usunąłem swój komentarz, ponieważ błędnie przeczytałem pytanie. – rfkortekaas

+0

Wpadłem na bardzo podobny problem, ale nie robiliśmy nic pod względem obliczeniowym. Wydaje się, że jest problem z wyłapywaniem właściwego "socketio" podczas wywoływania socketio.emit. Ponieważ emituje się TO, ale żaden klient nie otrzymuje wiadomości. Dodanie async_mode = 'threading' wydawało się naprawić problem. Ale mam nadzieję, że jest lepszy sposób. – AMB0027

Odpowiedz