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]