threading =真正的烧瓶 - socketio

Bru*_*rin 9 flask flask-socketio

我一直在使用flask,我的一些路由处理程序开始计算可能需要几分钟才能完成.使用flask的开发服务器,我可以使用app.run(threaded = True),我的服务器将在执行这些多分钟计算时继续响应其他请求.

现在我开始使用Flask-SocketIO,我不知道如何做同样的事情.我明白,只要它启动其中一个计算,我就可以在python中显式生成一个单独的线程.这是唯一的方法吗?或者是否有类似于threaded = true的东西,用于烧瓶 - socketio.(或者,更可能的是,我只是完全糊涂了.)

谢谢你的帮助.

Mig*_*uel 17

Flask/Werkzeug中的线程模式的想法是使开发服务器能够同时处理多个请求.在默认模式下,服务器一次可以处理一个请求,如果客户端在服务器处理先前请求时发送请求,则第二个请求必须等到第一个请求完成.在线程模式下,Werkzeug为每个传入请求生成一个线程,因此可以同时处理多个请求.您显然正在利用线程模式来获取需要很长时间才能返回的请求,同时保持服务器对其他请求的响应.

请注意,当您移出开发Web服务器并进入生产Web服务器时,此方法很难正确扩展.对于基于工作服务器的服务器,您必须选择固定数量的工作程序,这样才能获得可以拥有的最大并发请求数.

另一种方法是使用基于协程的服务器,例如gevent,Flask完全支持.对于gevent,只有一个工作进程,但是在其中有多个轻量级(或"绿色")线程,它们可以相互允许彼此运行.在这种模式下工作的关键是确保这些绿色线程不会滥用他们获得的CPU时间,因为一次只能运行一个.如果做得好,服务器可以比我上面描述的多工作方法更好地扩展,并且您可以轻松地以这种方式处理数百/数千个客户端.

所以现在你想使用Flask-SocketIO,这个扩展需要使用gevent.如果不清楚此要求的原因,与HTTP请求不同,SocketIO使用WebSocket协议,这需要长期连接.使用gevent和绿色线程可以使潜在的大量持续连接的客户端成为可能,这对多个工作人员来说是不可能的.

问题是您的长计算,这对gevent类型的服务器不友好.为了使它工作,你需要确保你的计算函数经常产生,这样其他线程就有机会运行而不会饿死.例如,如果您的计算函数有一个循环,您可以执行以下操作:

def my_long_calculation():
    while some_condition:
        # do some work here

        # let other threads run
        gevent.sleep()
Run Code Online (Sandbox Code Playgroud)

sleep()函数将基本上停止您的线程并切换到任何其他需要CPU的线程.最终控制权将返回给您的函数,此时它将继续进行下一次迭代.您需要确保睡眠呼叫没有太多间隔(因为这将使应用程序的其余部分无响应)或不太接近(因为这可能会减慢您的计算速度).

所以要回答你的问题,只要你在长时间的计算中正确屈服,你就不需要做任何特别的事情来处理并发请求,因为这是gevent的正常操作模式.

如果由于任何原因无法获得yield方法,那么您可能需要考虑将CPU密集型任务卸载到另一个进程.也许使用Celery将这些作为一个工作队列完成.

很抱歉这个冗长的回答.希望这可以帮助!