def coroutine(func): @functools.wraps(func) def wrapper(*args, **kwargs): future = TracebackFuture() if 'callback' in kwargs: print("gen.coroutine callback:{}".format(kwargs['callback'])) callback = kwargs.pop('callback') IOLoop.current().add_future( future, lambda future: callback(future.result())) try: print("gen.coroutine run func:{}".format(func)) result = func(*args, **kwargs) except (Return, StopIteration) as e: result = getattr(e, 'value', None) except Exception: future.set_exc_info(sys.exc_info()) return future else: if isinstance(result, types.GeneratorType): def final_callback(value): deactivate() print("gen.coroutine final set_result:{}".format(value)) future.set_result(value) print("gen.coroutine will Runner.run() result:{}".format(result)) runner = Runner(result, final_callback) runner.run() return future print("@@ gen.coroutine will set_result and return:{}".format(result)) future.set_result(result) return future return wrapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
st=>start: create future object rf=>operation: run function ex=>condition: is not exception gen=>condition: is generator run=>operation: Runner.run() fts=>operation: future.set_done() rtnf=>operation: return future ed=>end
def result(self, timeout=None): self._clear_tb_log() if self._result is not None: return self._result if self._exc_info is not None: raise_exc_info(self._exc_info) self._check_done() return self._result
def add_done_callback(self, fn): if self._done: fn(self) else: self._callbacks.append(fn)
def set_result(self, result): self._result = result self._set_done()
def _set_done(self): self._done = True for cb in self._callbacks: try: cb(self) except Exception: app_log.exception('Exception in callback %r for %r', cb, self) self._callbacks = None