python - Tornado 协程在 Cython 中不起作用

标签 python generator tornado cython coroutine

此代码在使用 Tornado 4.1 的 Python 3.4.3 中运行 - 它休眠 1 秒,然后打印“Hello World! 123”。但是当使用 Cython 编译时(我尝试了版本 0.20.1post0 和 0.23dev),它什么也没做。

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'

最佳答案

更新:从 Tornado 4.3 开始原生支持 Cython 协程。以下解决方法仅适用于旧版本的 Tornado。


Cython 目前不支持 Tornado 协程。主要问题是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)

关于python - Tornado 协程在 Cython 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30434838/

相关文章:

python - 将值从一个列表复制到另一个列表而不更改 python 中的引用

python - 比较两个 Python 3 日期时间对象返回 "can' t 比较原始偏移和偏移感知日期时间 : TypeError"

python - 使用列表中定义的多个条件过滤 Pandas 数据框

python - 有没有办法在换行符很重要的纯文本文件中使用 Mako 模板?

javascript - ES6 生成器让我感到困惑

python - Tornado 脚本在实时主机上获取响应代码 500

c - 为什么我的程序会给我多余的输出? C程序

java - 如何在android中生成随机事件?

python - 错误 : types. coroutine() expects a callable

mysql - Tornado -mysql插入不工作