>>>from twisted.internet import reactor >>>reactor <twisted.internet.selectreactor.SelectReactor object at 0x01C5BFD0>
reactor本来是一个模块,怎么变成对象了?
查看 reactor.py, 看到就一个模块方法selectreactor.install()
查看install方法:
def install(): """Configure the twisted mainloop to be run using the select() reactor. """ reactor = SelectReactor() from twisted.internet.main import installReactor installReactor(reactor)
这里生成了一个SelectReactor的对象,似乎就是我们要找的reactor.
再查看main.py
def installReactor(reactor): # this stuff should be common to all reactors. import twisted.internet import sys assert not sys.modules.has_key('twisted.internet.reactor'), \ "reactor already installed" twisted.internet.reactor = reactor sys.modules['twisted.internet.reactor'] = reactor
哦, reactor已经被偷梁换柱了.
回到selectreactor.py, 看看 SelectReactor 类是个什么东西.
SelectReactor 继承父类posixbase.PosixReactorBase, 本身增加了一些方法, 似乎看不出什么.那我们就去posixbase.py看看他爸爸是干什么的.
PosixReactorBase继承两个父类_SignalReactorMixin 和 ReactorBase. 先不管其他, 寻根溯源,这两个父类都来自于internet.base模块.
好吧, 找到这里算是到头了. ReactorBase 作为 "Reactor" 的基类, 提供了reactor大部分及其重要的方法, 另一些重要的方法由_SignalReactorMixin来扩展. 下面做下详细的分析.
# 一般来说, 建立一个服务器基本遵循以下几个步骤 # 以建立一个最基本的TCP服务器为例 #1 reactor.listenTCP(PORT, Factory()) #2 reactor.run()
对于#1比较好理解, 在posixbase.PosixReactorBase中
def listenTCP(self, port, factory, backlog=50, interface=''): """@see: twisted.internet.interfaces.IReactorTCP.listenTCP """ p = tcp.Port(port, factory, backlog, interface, self) p.startListening() return p # 其中包括socket的建立,绑定等等一系列手续. # 详细内容以后再表.
对于#2, 在base.SignalReactorMixin中
def run(self, installSignalHandlers=True): self.startRunning(installSignalHandlers=installSignalHandlers) self.mainLoop() def mainLoop(self): while self._started: try: while self._started: # Advance simulation time in delayed event # processors. self.runUntilCurrent() t2 = self.timeout() t = self.running and t2 self.doIteration(t) except: log.msg("Unexpected error in main loop.") log.err() else: log.msg('Main loop terminated.')
reactor一直孜孜不倦地执行两个方法:self.runUntilCurrent和 self.doIteration. 看看这两个函数都是干什么的:
# 在ReactorBase中, runUntilCurrent方法主要做了两件事, # 把self.threadCallQueue和self.pendingTimedCalls 里的对象执行一遍 def runUntilCurrent(self): if self.threadCallQueue: # Keep track of how many calls we actually make, as we're # making them, in case another call is added to the queue # while we're in this loop. count = 0 total = len(self.threadCallQueue) for (f, a, kw) in self.threadCallQueue: try: f(*a, **kw) except: log.err() count += 1 if count == total: break del self.threadCallQueue[:count] if self.threadCallQueue: if self.waker: self.waker.wakeUp() # insert new delayed calls now self._insertNewDelayedCalls() now = self.seconds() while self._pendingTimedCalls and (self._pendingTimedCalls[0].time <= now): call = heappop(self._pendingTimedCalls) if call.cancelled: self._cancellations-=1 continue if call.delayed_time > 0: call.activate_delay() heappush(self._pendingTimedCalls, call) continue try: call.called = 1 call.func(*call.args, **call.kw) except: log.deferr() if hasattr(call, "creator"): e = "\n" e += " C: previous exception occurred in " + \ "a DelayedCall created here:\n" e += " C:" e += "".join(call.creator).rstrip().replace("\n","\n C:") e += "\n" log.msg(e) if (self._cancellations > 50 and self._cancellations > len(self._pendingTimedCalls) >> 1): self._cancellations = 0 self._pendingTimedCalls = [x for x in self._pendingTimedCalls if not x.cancelled] heapify(self._pendingTimedCalls) if self._justStopped: self._justStopped = False self.fireSystemEvent("shutdown")
# 回到SelectReactor中,查看 doSelect(doIteration)方法 # _select既是select.select函数 # self._reads和self._writes内存储的应该都是类文件操作符,比如socket.. # 再看下self._doReadOrWrite方法,会发现所有的reader/writer都执行自身 # 的 doRead/doWrite方法. def doSelect(self, timeout): """ Run one iteration of the I/O monitor loop. This will run all selectables who had input or output readiness waiting for them. """ while 1: try: r, w, ignored = _select(self._reads.keys(), self._writes.keys(), [], timeout) break except ValueError, ve: # Possibly a file descriptor has gone negative? log.err() self._preenDescriptors() except TypeError, te: # Something *totally* invalid (object w/o fileno, non-integral # result) was passed log.err() self._preenDescriptors() except (select.error, IOError), se: # select(2) encountered an error if se.args[0] in (0, 2): # windows does this if it got an empty list if (not self._reads) and (not self._writes): return else: raise elif se.args[0] == EINTR: return elif se.args[0] == EBADF: self._preenDescriptors() else: # OK, I really don't know what's going on. Blow up. raise _drdw = self._doReadOrWrite _logrun = log.callWithLogger for selectables, method, fdset in ((r, "doRead", self._reads), (w,"doWrite", self._writes)): for selectable in selectables: # if this was disconnected in another thread, kill it. # ^^^^ --- what the !@#*? serious! -exarkun if selectable not in fdset: continue # This for pausing input when we're not ready for more. _logrun(selectable, _drdw, selectable, method, dict)
好吧,从上面基本可以看出, reactor在run循环里做了两件事, 执行线程队列和延迟对象队列,操作类文件对象符.
对于线程队列和延迟对象队列, 还比较好理解.
对于类文件对象的队列, reactor 是什么时候把它们加进的呢?