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?
@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
Usunąłem swój komentarz, ponieważ błędnie przeczytałem pytanie. – rfkortekaas
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