2015-06-17 49 views
6

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

现在我已经开始使用Flask-SocketIO,我不知道如何做同样的事情。我知道,我可以在python的任何时候显式地产生一个单独的线程,从任何时候开始这些计算之一。这是做到这一点的唯一方法吗?或者是否存在与flask-socketio的threaded = True相同的内容。 (或者更可能是我完全困惑。)

感谢您的任何帮助。

回答

13

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

请注意,当您离开开发Web服务器并进入生产Web服务器时,此方法难以正确扩展。对于基于服务器的服务器,您必须选择固定数量的工作人员,并为您提供最大数量的并发请求。

另一种方法是使用基于协同程序的服务器,例如gevent,它完全受Flask支持。对于gevent来说,只有一个工作进程,但其中有多个轻量级(或“绿色”)线程,它们协作允许对方运行。在这种模式下工作的关键是确保这些绿色线程不会滥用CPU时间,因为一次只能运行一个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() 

sleep()功能将基本遏制你的线程,并切换到需要CPU的任何其他线程。最终控制权将返回给您的功能,并在此时进入下一次迭代。您需要确保睡眠呼叫不会太远(因为这会使应用程序的其余部分无响应)或不太接近(因为这可能会减慢计算速度)。

因此,要回答你的问题,只要你在较长的计算正确屈服,你不需要做任何特殊处理的并发请求,因为这是GEVENT的正常工作模式。

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

对不起,冗长的回答。希望这可以帮助!

+0

非常感谢米格尔对此的回应。 (我会早一点感谢你,但我不在度假。)这非常明显有帮助。 –