tornado.util.Configurable是tornado.ioloop.IOLoop的基类,使用了元类编程的方式,重写了__new__函数, 改变了其创建类的方式。在此, 只是记载一下其类的初始化调用过程。
def __new__(cls, *args, **kwargs): base = cls.configurable_base() #这个函数必须要求在子类中实现,结合下面的代码,个人理解是在修改最终要初始化的类。如果返回值并不是当前new的类,就不必瞎折腾了。 init_kwargs = {} if cls is base: impl = cls.configured_class() #这个函数实现就在Configurable中,主要是调用了子类的configurable_default函数。该函数就返回了最终要初始化的类 if base.__impl_kwargs: init_kwargs.update(base.__impl_kwargs) else: impl = cls init_kwargs.update(kwargs) instance = super(Configurable, cls).__new__(impl) instance.initialize(*args, **init_kwargs) #调用需要初始化类的initialize return instance @classmethod def configured_class(cls): base = cls.configurable_base() if cls.__impl_class is None: base.__impl_class = cls.configurable_default() return base.__impl_class
以IOLoop为例:
@classmethod def configurable_default(cls): if hasattr(select, "epoll"): # Linux from tornado.platform.epoll import EPollIOLoop return EPollIOLoop if hasattr(select, "kqueue"): # BSD or Mac from tornado.platform.kqueue import KQueueIOLoop return KQueueIOLoop from tornado.platform.select import SelectIOLoop #如果都不行, 那就只能用select了 return SelectIOLoop @staticmethod def instance(): if not hasattr(IOLoop, "_instance"): #单例模式 with IOLoop._instance_lock: #避免同时初始化 if not hasattr(IOLoop, "_instance"): #再判断一次, 保证真的只是单例的 IOLoop._instance = IOLoop() return IOLoop._instance def initialize(self, make_current=None): #make_current看起来像是在标识是不是要强制创建 if make_current is None: if IOLoop.current(instance=False) is None: self.make_current() elif make_current: if IOLoop.current(instance=False) is not None: #已经初始化过了? raise RuntimeError("current IOLoop already exists") self.make_current() def make_current(self): IOLoop._current.instance = self
本人使用的系统是ubuntu,所以最后返回的是EPollIOLoop。
def initialize(self, **kwargs): super(EPollIOLoop, self).initialize(impl=select.epoll(), **kwargs) #由于EPollIOLoop是PollIOLoop的子类,所以又需要定位到父类查看了
PollIOLoop:
def initialize(self, impl, time_func=None, **kwargs): super(PollIOLoop, self).initialize(**kwargs) self._impl = impl if hasattr(self._impl, 'fileno'): set_close_exec(self._impl.fileno()) self.time_func = time_func or time.time self._handlers = {} self._events = {} self._callbacks = [] self._callback_lock = threading.Lock() self._timeouts = [] self._cancellations = 0 self._running = False self._stopped = False self._closing = False self._thread_ident = None self._blocking_signal_threshold = None self._timeout_counter = itertools.count() self._waker = Waker() self.add_handler(self._waker.fileno(), #这里只是将读的一段加入。源注释是说创建Pipe, 在需要的时候唤醒IOLoop。另一端在那里?? lambda fd, events: self._waker.consume(), self.READ) def add_handler(self, fd, handler, events): fd, obj = self.split_fd(fd) self._handlers[fd] = (obj, stack_context.wrap(handler)) self._impl.register(fd, events | self.ERROR) def split_fd(self, fd): try: return fd.fileno(), fd except AttributeError: return fd, fd def close(self, all_fds=False): with self._callback_lock: self._closing = True self.remove_handler(self._waker.fileno()) #先pop出来, 最后才close if all_fds: for fd, handler in self._handlers.values(): self.close_fd(fd) self._waker.close() self._impl.close() self._callbacks = None self._timeouts = None
Waker
class Waker(interface.Waker): #pipe的方式 def __init__(self): r, w = os.pipe() _set_nonblocking(r) _set_nonblocking(w) set_close_exec(r) set_close_exec(w) self.reader = os.fdopen(r, "rb", 0) self.writer = os.fdopen(w, "wb", 0) def fileno(self): return self.reader.fileno() def write_fileno(self): return self.writer.fileno() def wake(self): try: self.writer.write(b"x") except IOError: pass def consume(self): try: while True: result = self.reader.read() if not result: break except IOError: pass def close(self): self.reader.close() self.writer.close()