探索eventlet通信机制
一、源码解析
对python原生文件打补丁:
import eventlet
eventlet.monkey_patch()
跟踪进入该模块方法:eventlet.patcher#monkey_patch
def monkey_patch(**on):
......
modules_to_patch = []
for name, modules_function in [
('os', _green_os_modules),
('select', _green_select_modules),
('socket', _green_socket_modules),
('thread', _green_thread_modules),
('time', _green_time_modules),
('MySQLdb', _green_MySQLdb),
('builtins', _green_builtins),
('subprocess', _green_subprocess_modules),
]:
if on[name] and not already_patched.get(name):
modules_to_patch += modules_function()
already_patched[name] = True
......
该方法对某些系统模块进行全局打补丁,使其对Greenthread友好。关键字参数用于指定哪些模块需要打补丁,如果未提供关键字参数,则会对所有默认的模块(如代码所示)打补丁,例如: monkey_patch(socket = True,select = True)
仅对socket和select模块打补丁。大多数参数都是对同名的单个模块进行打补丁,比如操作系统,时间,选择。但是socket例外,它也会对ssl模块(如果存在)打补丁,thread用于对threading、thread、Queue打补丁。说明:多次调用monkey_patch是安全的。
以socket为例:('socket', _green_socket_modules)
,进入该方法:
def _green_socket_modules():
from eventlet.green import socket
try:
from eventlet.green import ssl
return [('socket', socket), ('ssl', ssl)]
except ImportError:
return [('socket', socket)]
进入socket模块:eventlet.green.socket
__import__('eventlet.green._socket_nodns')
__socket = sys.modules['eventlet.green._socket_nodns']
__all__ = __socket.__all__
__patched__ = __socket.__patched__ + [
'create_connection',
'getaddrinfo',
'gethostbyname',
'gethostbyname_ex',
'getnameinfo',
]
在进入eventlet.green._socket_nodns:
__socket = __import__('socket')
__all__ = __socket.__all__
__patched__ = ['fromfd', 'socketpair', 'ssl', 'socket', 'timeout']
可以看到是对python的原生socket模块进行了打补丁:pythonx.x/Lib/socket.py 以socket类为例:python原生的socket.socket()类并替换为了eventlet.greenio.base#GreenSocket类 该补丁类完全兼容原生socket类的API,它还可以识别关键字参数set_nonblocking = True
。用来设置socket为非阻塞模式。
class GreenSocket(object):
# This placeholder is to prevent __getattr__ from creating an infinite call loop
fd = None
def __init__(self, family=socket.AF_INET, *args, **