def start(self):
"""Starts the I/O loop.
The loop will run until one of the I/O handlers calls stop(), which
will make the loop stop after the current event iteration completes.
"""
self._running = True
while True:
[ ... ]
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, 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)
里边是这么遍历一个dict数据的
while self._events:
fd, events = self._events.popitem()
为什么不采用下面这种常用遍历方式呢
for fd, events in self._events.items():
原因很简单,在主循环期间,这个_events字典变量可能会被处理器所修改。比如remove_handler()处理器。这个方法把fd从_events字典中取出,
所以即使fd被选择到了,它的处理器也不会被调用,如果使用for迭代循环_events,那么在迭代期间_events就不能被修改,否则会产生不可预计的错误,
比如,明明调用了 remove_handler()方法删除了某个键值对,但是该handler还是被调用了。