假设我们有一个WSGI应用程序,它托管在一个事件驱动的单线程服务器上:
from eventlet import wsgi
import eventlet
def app(env, start_response):
# IO opeartions here
...
wsgi.server(eventlet.listen(('', 8090)), app)
在app功能中,必须执行一些I / O操作,如读取文件或DB访问。
现在,当我们在app中执行IO操作时,服务器被有效阻止,无法为其他客户端提供服务。
问:这个问题有哪些可行的解决方案?如何在不被阻止的情况下让Eventlet wsgi服务器执行耗时的操作?
答案 0 :(得分:0)
TL; DR:使用mysqldb / psycopg或eventlet.import_patched()
纯python DB驱动程序; tpool.execute()
用于存放文件和其他所有内容。
尝试将您的思维过程修复为分离操作,这些操作可以转换为与Eventlet的合作以及那些不可能的合作。这里的合作意味着分成“执行代码” - “等待结果”部分,并在结果准备好时提供通知机制。 Eventlet的主要通知机制是文件描述符。
所以等待文件描述符的一切都是绿色(不阻塞)的候选者。最重要的是,它会影响所有网络IO。如果您的阻塞函数是用纯Python编写的,只需使用import_patched(module_name)
修改其socket
和其他对Eventlet绿色版本的引用。 mysqldb
和psycopg2
是C扩展模块的特殊情况,合作感谢其作者的明确支持。非Python代码中阻塞的所有其他内容 - 您的选项是操作系统线程。
不幸的是,等待实际的磁盘文件充满了怪癖,所以我建议使用操作系统线程,我们有内置的线程池来支持它。将blocking_fun(filepath, something_else)
转换为eventlet.tpool.execute(blocking_fun, filepath, something_else)
并且它不会阻止所有内容。查看tpool文档了解详细信息。
如果可以,请将整个应用程序重新设计为阻塞和非阻塞进程,并让它们通过套接字进行通信。从代码重写的角度来看这很难,但对于运行时调试非常简单;强大且防故障的设计。