0

あるスレッドでサーバーを起動し、別のスレッドで値プロデューサーを起動する必要があります (ここでは によって偽装されて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ラインだと思いますが、念のため。

4

1 に答える 1

2

Eventlet は協調マルチタスクを使用します。スレッド化、同期化、またはソケットなど、標準ライブラリの潜在的にブロックする関数を使用すると、サーバー全体がブロックされる危険性があります。

Eventlet は、ライブラリ内のほとんどのブロッキング関数の代替バージョンを提供するため、この種の問題を回避するにはそれらを使用する必要があります。イベントレットに適した関数に切り替える最も簡単な方法は、標準ライブラリにモンキー パッチを適用することです。

于 2019-12-03T07:08:05.453 に答える