Python 螺纹中的活瓶套筒

Python 螺纹中的活瓶套筒,python,flask,socket.io,eventlet,Python,Flask,Socket.io,Eventlet,我有一个交互式Python应用程序,其中我还想使用flask socketio与Javascript客户端进行交互。 因此,我需要Python socketio作为线程运行 方法#1: def socketio_server_fn(): socketio.run(flask_app, port=5000) flask_app = Flask(__name__) socketio = flask_socketio.SocketIO(flask_app, always_connect=Tru

我有一个交互式Python应用程序,其中我还想使用flask socketio与Javascript客户端进行交互。 因此,我需要Python socketio作为线程运行

方法#1:

def socketio_server_fn():
    socketio.run(flask_app, port=5000)
flask_app = Flask(__name__)
socketio = flask_socketio.SocketIO(flask_app, always_connect=True, async_mode='threading')
socketio_thread = socketio.start_background_task(socketio_server_fn)
问题1.1:它不使用Websocket传输,因为它与标准Python线程不兼容。相反,socketio又回到了投票

问题1.2:轮询不仅效率低下,而且每秒向控制台发送以下消息:

127.0.0.1--[2019年10月10日13:57:11]“GET/socket.io/?EIO=3&transport=polling&t=MsrXwsJ&sid=c63dfaefdbb84c68dd53bef2f6d3c77 HTTP/1.1”200-

我无法删除这些邮件,其他邮件的结果也非常复杂:

方法#2:使用eventlet

首先,我们需要在程序开始时修补Python线程系统:

import eventlet
eventlet.monkey_patch()
然后将SocketIO对象创建行更改为:

socketio = flask_socketio.SocketIO(flask_app, always_connect=True, async_mode='eventlet')
现在socketio使用Websocket

问题2.1:对于整个Python线程系统,我宁愿避免使用monkey_补丁

问题2.2:在拆卸应用程序时,使用eventlet似乎会破坏socketio.stop()。stop()现在即使从HTTP处理程序函数调用也会挂起。相同的拆卸代码同时适用于async_mode='threading'和普通的socketio.run()。socketio.server.stop()也挂起

问题2.3:Eventlet似乎与prompt_toolkit不完全兼容:

Exception in default exception handler
Traceback (most recent call last):
  File "python\lib\site-packages\prompt_toolkit\eventloop\win32.py", line 102, in _run_task
    t()
  File "python\lib\site-packages\prompt_toolkit\eventloop\context.py", line 116, in new_func
    return func(*a, **kw)
  File "python\lib\site-packages\prompt_toolkit\patch_stdout.py", line 103, in write_and_flush_in_loop
    run_in_terminal(write_and_flush, in_executor=False)
  File "python\lib\site-packages\prompt_toolkit\application\run_in_terminal.py", line 50, in run_in_terminal
    return run_coroutine_in_terminal(async_func, render_cli_done=render_cli_done)
  File "python\lib\site-packages\prompt_toolkit\application\run_in_terminal.py", line 71, in run_coroutine_in_terminal
    assert app._is_running
AssertionError
方法#3:使用gevent 这似乎根本不起作用


对于将flask socketio作为线程运行这一看似常见的用例,难道没有一个简单的解决方案吗?

因为这个问题获得了投票,我可以说我通过跳出框框思考解决了这个难题。我换了一个新的

我的解决方案是这样的(不完整的代码):

from aiohttp import web

class MyThreadedServer(Thread):

    def __init__(self):
        self._loop = None  # The event loop for the async web server

    async def _on_shutdown(self, app):
        for conn in set(self.connections):
            await conn.close()

    def run(self):
        #Runs a separate asyncio loop on this (separate) thread
        self._loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self._loop)
        self.stop_server = asyncio.Event()
        self._loop.run_until_complete(self._run_app())
        #Or in Python 3.7, simply:
        #  asyncio.run(run())
        self._loop.close()

    async def _run_app(self):
        self.app = web.Application()
        self.app.on_shutdown.append(self._on_shutdown)    
        runner = web.AppRunner(self.app)
        await runner.setup()
        site = web.TCPSite(runner, self.hostname, self.port)
        await site.start()
        print('Started web server on %s port %d' % (self.hostname, self.port))
        await self.stop_server.wait()
        print('Web server closing down')

    def stop(self):
        "Call from any thread"
        # Overrides EventThread.stop() to change implementation
        if self.stop_server:
            self._loop.call_soon_threadsafe(self.stop_server.set)