eventlet这个强悍的东东,看到我同事的一些整理。故贴出来,你们一块儿分享~python
114.113.199.11服务器上nova服务中基于python eventlet实现的定时任务(periodic_task)和 心跳任务(report_state)都是eventlet的一个greenthread实例.linux
目前服务器上出现了nova定时任务中某些任务执行时间过长而致使心跳任务不能准时运行的问题.git
若是eventlet是一个彻底意义上的相似线程/进程的并发库的话, 不该该出现这个问题, 须要研究 eventlet的并发实现, 了解它的并发实现原理, 避免之后出现相似的问题.github
通过阅读eventlet源代码, 能够知道eventlet主要依赖另外2个python package:web
主要作了3个工做:服务器
epoll是linux实现的一个基于事件的异步IO库, 在以前相似的异步IO库poll上改进而来.并发
下面两个例子会演示如何用epoll将阻塞的IO操做用epoll改写为异步非阻塞. (取自官方文档)异步
import socket EOL1 = b'\n\n' EOL2 = b'\n\r\n' response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' response += b'Hello, world!' serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind(('0.0.0.0', 8080)) serversocket.listen(1) try: while True: connectiontoclient, address = serversocket.accept() request = b'' while EOL1 not in request and EOL2 not in request: request += connectiontoclient.recv(1024) print('-'*40 + '\n' + request.decode()[:-2]) connectiontoclient.send(response) connectiontoclient.close() finally: serversocket.close()
这个例子实现了一个简单的监听在8080端口的web服务器. 经过一个死循环不停的接收来自8080端口 的链接, 并返回结果.socket
须要注意的是程序会在ide
connectiontoclient, address = serversocket.accept()
这一行block住, 直到获取到新的链接, 程序才会继续往下运行.
同时, 这个程序同一个时间内只能处理一个链接, 若是有不少用户同时访问8080端口, 必需要按前后 顺序依次处理这些链接, 前面一个链接成功返回后, 才会处理后面的链接.
下面的例子将用epoll将这个简单的web服务器改写为异步的方式
import socket, select EOL1 = b'\n\n' EOL2 = b'\n\r\n' response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' response += b'Hello, world!' serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind(('0.0.0.0', 8080)) serversocket.listen(1) serversocket.setblocking(0) epoll = select.epoll() epoll.register(serversocket.fileno(), select.EPOLLIN) try: connections = {}; requests = {}; responses = {} while True: events = epoll.poll(1) for fileno, event in events: if fileno == serversocket.fileno(): connection, address = serversocket.accept() connection.setblocking(0) epoll.register(connection.fileno(), select.EPOLLIN) connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = response elif event & select.EPOLLIN: requests[fileno] += connections[fileno].recv(1024) if EOL1 in requests[fileno] or EOL2 in requests[fileno]: epoll.modify(fileno, select.EPOLLOUT) print('-'*40 + '\n' + requests[fileno]