Cython:如何在没有 GIL 的情况下打印

Posted

技术标签:

【中文标题】Cython:如何在没有 GIL 的情况下打印【英文标题】:Cython: How to print without GIL 【发布时间】:2018-06-30 00:17:55 【问题描述】:

我应该如何在没有 gil 的 Cython 函数中使用 print?例如:

from libc.math cimport log, fabs
cpdef double f(double a, double b) nogil:
    cdef double c = log( fabs(a - b) )
    print c
    return c

编译时报此错误:

Error compiling Cython file:
...
    print c
    ^
------------------------------------------------------------

Python print statement not allowed without gil
...

我知道如何使用 C 库而不是它们的 python 等效库(此处以math 库为例),但我找不到print 的类似方法。

【问题讨论】:

为什么需要这个?你只需要真正释放 GIL 来执行多线程。在多个线程中使用print 很容易结束,最终会导致输出混乱。 @DavidW 我没有做任何多线程。我认为发布 GIL 会消除 Python 开销(这似乎是我错了?)。在我的例子中,我的代码的核心部分是一个大的 for 循环(大约 50 行代码),但这是我的猜测,我没有检查释放 GIL 是否有助于我的大代码。 听起来你不需要那么严格——仅仅拥有 GIL 不会让你慢下来。不需要 GIL 的代码通常更快(作为一般规则),但偶尔打印语句就可以了。 我认为这个有用的评论值得一看。我不知道什么是最好的,但请随时将其作为对我的问题的编辑或作为答案发布。 【参考方案1】:

使用来自stdioprintf

from libc.stdio cimport printf
...
printf("%f\n", c)

【讨论】:

【参考方案2】:

这是 cmets 讨论的后续内容,该讨论表明这个问题是基于一个轻微的误解:始终值得思考为什么需要发布 GIL 以及是否真的需要这样做。

从根本上说,GIL 是每个线程持有的标志,用于指示是否允许调用 Python API。简单地拿着旗帜不会让你失去任何表现。 Cython 在不使用 Python API 时通常最快,但这是因为它执行的操作类型而不是因为它持有标志(即 printf 可能比 Python print 稍快,但 printf 运行有或没有 GIL 的速度相同)。

您真正需要担心 GIL 的唯一情况是在使用多线程代码时,释放它可以让其他 Python 线程有机会运行。 (类似地,如果您正在编写一个库并且不需要 Python API,那么发布 GIL 可能是个好主意,这样您的用户可以根据需要运行其他线程)。

最后,如果您在 nogil 块中并且想要进行快速 Python 操作,您可以简单地执行以下操作:

with gil:
    print c

它可能不会花费您太多的性能,并且可以节省大量的编程工作。

【讨论】:

以上是关于Cython:如何在没有 GIL 的情况下打印的主要内容,如果未能解决你的问题,请参考以下文章

PySide/Cython 和 GIL 多线程使用

如何在 Cython 中调用多线程 C 函数?

分发 embed-cython-compiled .exe 并在没有 python 的情况下运行另一台机器

如何在pytest中使用Cython?

如何在没有“可选”的情况下从 plist 打印字符串?

如何在没有行终止符的情况下快速打印字符数组