Ioloop
ioloop 核心的I/O循环 Tornado为了实现高并发和高性能,使用了一个IOLoop事件循环来处理socket的读写事件,IOLoop事件循环是基于Linux的epoll模型,可以高效地响应网络事件,这是Tornado高效的基础保证。
目标
更好的理解ioloop的事件循环。
- 
    对应调用来进行阅读,首先找一份ioloop调用代码。 以下为ioloop源码中提供的代码,功能是一个tcp的服务端 
| 1 |  | 
- 
    ioloop.IOLoop.instance() 对用源码 1 
 2
 3
 4
 5
 6@classmethod def instance(cls): # 单例 if not hasattr(cls, "_instance"): cls._instance = cls() return cls._instance一个经典的单例模式 
- 
    io_loop.add_handler(sock.fileno(), callback, io_loop.READ) 对应源码 1 
 2
 3
 4
 5# 注册处理方法到对应的描述符上 def add_handler(self, fd, handler, events): """Registers the given handler to receive the given events for fd.""" self._handlers[fd] = handler self._impl.register(fd, events | self.ERROR)看起来比较简单的逻辑,将描述符和对应处理方法相绑定 self._impl.register 实际调用的epoll添加事件的方法 epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_ADD, fd, events) 
- 
    io_loop.start() 实现循环的核心逻辑 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63def start(self): self._running = True while True: # Never use an infinite timeout here - it can stall epoll poll_timeout = 0.2 # Prevent IO event starvation by delaying new callbacks # to the next iteration of the event loop. callbacks = list(self._callbacks) for callback in callbacks: # A callback can add or remove other callbacks if callback in self._callbacks: self._callbacks.remove(callback) self._run_callback(callback) if self._callbacks: poll_timeout = 0.0 if self._timeouts: now = time.time() while self._timeouts and self._timeouts[0].deadline <= now: timeout = self._timeouts.pop(0) self._run_callback(timeout.callback) if self._timeouts: milliseconds = self._timeouts[0].deadline - now poll_timeout = min(milliseconds, poll_timeout) if not self._running: break try: # 获取可读写事件 event_pairs = self._impl.poll(poll_timeout) except Exception, e: if e.args == (4, "Interrupted system call"): logging.warning("Interrupted system call", exc_info=1) continue else: raise # Pop one fd at a time from the set of pending fds and run # its handler. Since that handler may perform actions on # other file descriptors, there may be reentrant calls to # this IOLoop that update self._events self._events.update(event_pairs) while self._events: # 获取一个fd以及对应事件 fd, events = self._events.popitem() try: # 执行事件 self._handlers[fd](fd, events) except KeyboardInterrupt: raise except OSError, e: if e[0] == errno.EPIPE: # Happens when the client closes the connection pass else: logging.error("Exception in I/O handler for fd %d", fd, exc_info=True) except: logging.error("Exception in I/O handler for fd %d", fd, exc_info=True)self._impl.poll(poll_timeout)获取当前读写事件 实际调用 epoll.epoll_wait(self._epoll_fd, int(timeout * 1000)) 后续就比较简单查找读写事件的对应方法然后执行 
自己实现一个ioloop
实现一个简单版本能够完成上文客户端调用
| 1 |  | 
以上代码完成了客户端调取的全部功能
ps:select.epoll 只在py2.6以上的版本存在
测试客户端代码
| 1 |  | 
可以直接配置以上三个文件再本地进行测试更好的理解ioloop的用法
“世界就像是个巨大的马戏团,它让你兴奋,却让我惶恐,因为我知道散场后永远是有限温存,无限心酸。”