现在的位置: 首页 > 综合 > 正文

tornado之ioloop类源码分析 Tornado 之 IOLoop类分析

2018年04月12日 ⁄ 综合 ⁄ 共 4213字 ⁄ 字号 评论关闭

Tornado 之 IOLoop类分析

分类: Tornado 学习 http://blog.csdn.net/hpghy123456/article/details/9169241 962人阅读 评论(1) 收藏 举报

    源代码 Tornado 1-2-1

    IOLoop类是Tornado的边缘触发事件驱动模型,在Linux平台下面封装的是epoll模型,这个类的代码也很简单,比Nginx好看多了。

    先看属性:

            _handlers保存(fd,handler)的映射关系,_events保存就绪的fd以及对应的events事件(读/写/错误),_blocking_signal_threshold表示超时阈值,如果不为None,当select.poll()返回后,调用fd对应的handler工作时间超过这个值时,就会触发SIGALRM信号,set_blocking_signal_threshold可以设置这个阈值,并安装SIGALRM信号处理函数。_callbacks 存储的是一些函数对象(回调函数),具体作用暂且不懂。

     方法分析:

1、初始化:注意管道的作用,和Nginx的进程模型类似,管道也是用于其他进程向ioloop.start()进程发送命令。Tornado中不解析命令,只是简单的退出监听循环。

[python] view
plain
copy

  1. def __init__(self, impl=None):  
  2.         .....  
  3.     # hp: 管道,用来发送命令给epoll_wait进程. 在这里只是为了唤醒epoll.poll()/epoll_wait,接着退出ioloop循环,停止监听事件  
  4.         if os.name != 'nt':  
  5.             r, w = os.pipe()  
  6.             self._set_nonblocking(r)  
  7.             self._set_nonblocking(w)  
  8.             self._set_close_exec(r)  
  9.             self._set_close_exec(w)  
  10.             self._waker_reader = os.fdopen(r, "rb"0)      # hp: fdopen convert fileno to FILE*, bufsize=0  
  11.             self._waker_writer = os.fdopen(w, "wb"0)  
  12.         else:  
  13.             .....         
  14.   
  15.     # hp: 只监听管道读事件,读取其他进程发送给ioloop进程的命令,使得ioloop退出监听循环  
  16.         self.add_handler(r, self._read_waker, self.READ)  

2、add_handler, update_handler、remove_handler就是简单的对epoll_ctl的封装,没有什么特殊的地方。
3、start函数,进程的监听循环,循环监听所有的fd,并调用fd对应的handler,和Nginx类似。
[python] view
plain
copy

  1. def start(self):  
  2.         if self._stopped:  
  3.             self._stopped = False  
  4.             return  
  5.         self._running = True  
  6.         while True:  
  7.             poll_timeout = 0.2  
  8.             callbacks = self._callbacks  
  9.             self._callbacks = []  
  10.             for callback in callbacks:  
  11.                 self._run_callback(callback)  
  12.   
  13.             if self._callbacks:     # hp: 现在还没有看  
  14.                 poll_timeout = 0.0  
  15.                   
  16.     # hp: 定时机制和Nginx一模一样   
  17.             if self._timeouts:      # hp: 定时事件列表  
  18.                 now = time.time()  
  19.         # hp: 处理超时的事件  
  20.                 while self._timeouts and self._timeouts[0].deadline <= now:  
  21.                     timeout = self._timeouts.pop(0)  
  22.                     self._run_callback(timeout.callback)  
  23.                 if self._timeouts:  
  24.                     milliseconds = self._timeouts[0].deadline - now  
  25.         # hp: 时间设置和Nginx一样,取下一个定时事件的时间  
  26.                     poll_timeout = min(milliseconds, poll_timeout)  
  27.   
  28.             if not self._running:   # hp: 调用stop()设置为false,通过管道给epoll发送消息,epoll醒来便退出循环  
  29.                 break  
  30.   
  31.             if self._blocking_signal_threshold is not None:  
  32.                 # clear alarm so it doesn't fire while poll is waiting for  
  33.                 # events.  
  34.         # hp: 清空之前的定时器  
  35.                 signal.setitimer(signal.ITIMER_REAL, 00)  
  36.   
  37.             try:  
  38.                 event_pairs = self._impl.poll(poll_timeout)  
  39.             except Exception, e:  
  40.                 ...  
  41.   
  42.         # hp: 安装定时器  
  43.             if self._blocking_signal_threshold is not None:  
  44.                 signal.setitimer(signal.ITIMER_REAL,  
  45.                                  self._blocking_signal_threshold, 0)   
  46.             self._events.update(event_pairs)  
  47.             while self._events:  
  48.                 fd, events = self._events.popitem()  
  49.                 try:  
  50.             # hp: 处理激活的fd  
  51.                     self._handlers[fd](fd, events)  
  52.                 except   
  53.     # 退出监听循环  
  54.         # reset the stopped flag so another start/stop pair can be issued  
  55.         self._stopped = False  
  56.         if self._blocking_signal_threshold is not None:  
  57.             # hp: 清除定时器  
  58.             signal.setitimer(signal.ITIMER_REAL, 00)  

4、stop函数:自己还不太习惯在面向对象编程中操作进程(习惯用C语言),比如:如何调用stop()函数,当前进程已经在start()中的epoll.poll中阻塞了,当前进程已经不能调用stop(),其他子进程中的ioloop对象处于不同的进程空间,只用把IOLoop的实例放入共享内存中,其他进程才能调用stop()从而终止当前进程的epoll循环。

[python] view
plain
copy

  1. def stop(self):  
  2.         self._running = False  
  3.         self._stopped = True  
  4.         self._wake()  
  5. def _wake(self):  
  6.         '''''hp: 退出当前的epoll_wait调用'''  
  7.         try:  
  8.             self._waker_writer.write("x")  
  9.         except IOError:  
  10.             pass  

参考


抱歉!评论已关闭.