2014-05-06 16 views

risposta

4

Come la documentazione tornado per gen.engine dice:

Questo decoratore è simile a coroutine, tranne che non restituisce un futuro e l'argomento callback non è trattata in modo speciale.

E come la documentazione gen.coroutine dice

Dal punto di vista del chiamante, @ gen.coroutine è simile alla combinazione di @return_future e @ gen.engine.

gen.engine è fondamentalmente una versione meno recente e semplificata di ciò che fa la coroutine. Se stai scrivendo un nuovo codice, dovresti seguire i consigli della documentazione e usare sempre tornado.gen.coroutine.

È piuttosto evidente se si guarda il codice per entrambe le funzioni (con la documentazione rimossa).

motore:

def engine(func): 
    @functools.wraps(func) 
    def wrapper(*args, **kwargs): 
     runner = None 

     def handle_exception(typ, value, tb): 
      if runner is not None: 
       return runner.handle_exception(typ, value, tb) 
      return False 
     with ExceptionStackContext(handle_exception) as deactivate: 
      try: 
       result = func(*args, **kwargs) 
      except (Return, StopIteration) as e: 
       result = getattr(e, 'value', None) 
      else: 
       if isinstance(result, types.GeneratorType): 
        def final_callback(value): 
         if value is not None: 
          raise ReturnValueIgnoredError(
           "@gen.engine functions cannot return values: " 
           "%r" % (value,)) 
         assert value is None 
         deactivate() 
        runner = Runner(result, final_callback) 
        runner.run() 
        return 
      if result is not None: 
       raise ReturnValueIgnoredError(
        "@gen.engine functions cannot return values: %r" % 
        (result,)) 
      deactivate() 
      # no yield, so we're done 
    return wrapper 

coroutine:

def coroutine(func): 
    @functools.wraps(func) 
    def wrapper(*args, **kwargs): 
     runner = None 
     future = TracebackFuture() 

     if 'callback' in kwargs: 
      callback = kwargs.pop('callback') 
      IOLoop.current().add_future(
       future, lambda future: callback(future.result())) 

     def handle_exception(typ, value, tb): 
      try: 
       if runner is not None and runner.handle_exception(typ, value, tb): 
        return True 
      except Exception: 
       typ, value, tb = sys.exc_info() 
      future.set_exc_info((typ, value, tb)) 
      return True 
     with ExceptionStackContext(handle_exception) as deactivate: 
      try: 
       result = func(*args, **kwargs) 
      except (Return, StopIteration) as e: 
       result = getattr(e, 'value', None) 
      except Exception: 
       deactivate() 
       future.set_exc_info(sys.exc_info()) 
       return future 
      else: 
       if isinstance(result, types.GeneratorType): 
        def final_callback(value): 
         deactivate() 
         future.set_result(value) 
        runner = Runner(result, final_callback) 
        runner.run() 
        return future 
      deactivate() 
      future.set_result(result) 
     return future 
    return wrapper 

Entrambi questi sono probabilmente abbastanza difficile da capire a prima vista. Tuttavia, è ovvio che il codice è molto simile, ad eccezione del fatto che lo @gen.coroutine ha una gestione speciale del kwarg callback e crea/restituisce un Future. @gen.engine ha un codice che genera in modo specifico un errore se si tenta di restituire qualcosa da esso, anziché inserirlo in Future.

Problemi correlati