2015-05-25 3 views
2

Этот код работает в Python 3.4.3 с использованием Tornado 4.1 - он спит в течение 1 секунды, а затем печатает «Hello World! 123». Но когда компилируется с помощью Cython (я пробовал версии 0.20.1post0 и 0.23dev), он ничего не делает.Tornado coroutines не работает в Cython

import tornado.ioloop 
import datetime 
from tornado import gen 

@gen.coroutine 
def test(): 
    yield gen.Task(ioloop.add_timeout, datetime.timedelta(seconds=1)) 
    return 123 

@gen.coroutine 
def hello_world(): 
    print('Hello World! {}'.format((yield test()))) 

ioloop = tornado.ioloop.IOLoop().instance() 
ioloop.run_sync(hello_world) 

Команды я использовал для создания и запуска версии Cython:

cython --embed -o hello.c hello.py 
gcc -shared -fPIC -O0 -Wall -I/usr/include/python3.4 -o hello.so hello.c 
python -c 'import hello' 
+0

Есть много сообщения об ошибках, связанные с cython и сопрограммами, это более чем вероятно другой. –

ответ

3

Update: Cython Сопрограммы изначально поддерживается начиная с Tornado 4.3. Обходной путь ниже - это только для старых версий Tornado.


Tornado coroutines в настоящее время не поддерживаются Cython. Основная проблема заключается в том, что генератор, скомпилированный Cython, не проходит isinstance(types.GeneratorType) (и в последний раз, когда я смотрел, не было другого класса, который мог бы использоваться вместо него).

Наилучшим решением для этого было бы изменение в Cython добавить общий базовый класс для генераторов, но как быстрый хак я имел некоторый успех с этим патчем к tornado/gen.py:

diff --git a/tornado/gen.py b/tornado/gen.py 
index aa931b4..b348f21 100644 
--- a/tornado/gen.py 
+++ b/tornado/gen.py 
@@ -91,6 +91,12 @@ from tornado.concurrent import Future, TracebackFuture 
from tornado.ioloop import IOLoop 
from tornado.stack_context import ExceptionStackContext, wrap 

+def _is_generator(obj): 
+ # cython generates a new generator type for each module without a 
+ # common base class :(
+ return (isinstance(obj, types.GeneratorType) or 
+   str(type(obj)) == "<type 'generator'>") 
+ 

class KeyReuseError(Exception): 
    pass 
@@ -147,7 +153,7 @@ def engine(func): 
      except (Return, StopIteration) as e: 
       result = getattr(e, 'value', None) 
      else: 
-    if isinstance(result, types.GeneratorType): 
+    if _is_generator(result): 
        def final_callback(value): 
         if value is not None: 
          raise ReturnValueIgnoredError(
@@ -219,7 +225,7 @@ def coroutine(func): 
       future.set_exc_info(sys.exc_info()) 
       return future 
      else: 
-    if isinstance(result, types.GeneratorType): 
+    if _is_generator(result): 
        def final_callback(value): 
         deactivate() 
         future.set_result(value) 
+1

Это сделало трюк, спасибо! Btw, он должен быть '' "' для Python 3. –

+0

Hah, Twisted делает то же самое, и я сделал подобный взлом там, когда я его использовал. –

Смежные вопросы