Cython: 如何在没有GIL的情况下进行打印输出

16

我应该如何在没有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

我知道如何使用 C 库替代其 Python 等效库(例如这里的 math 库),但我找不到类似的方法来替代 print 。


2
你为什么需要这个?你只需要释放GIL来进行多线程操作。从多个线程使用print可能最终只会产生混乱的输出。 - DavidW
@DavidW 我没有进行任何多线程操作。我认为释放GIL会消除Python的开销(但似乎我错了?)。在我的情况下,我的代码的核心部分是一个大型for循环(大约有50行代码),但这只是我的猜测,我没有检查释放GIL是否有助于我的大型代码。 - Behzad Jamali
1
听起来你不需要对此过于严格 - 仅仅拥有GIL并不会减慢你的速度。那些不需要GIL的代码通常更快(作为一般规则),但偶尔的打印语句也没关系。 - DavidW
我认为这个有用的评论值得被看到。我不知道什么是最好的,但请随意将其作为对我的问题的编辑或答案发布。 - Behzad Jamali
2个回答

31

使用来自stdioprintf函数:

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

19

这篇文章是对评论区的讨论的跟进,评论中提到这个问题基于一些误解:始终考虑释放GIL的原因以及是否真正需要这样做。

从根本上讲,GIL是每个线程持有的标志,用于指示其是否被允许调用Python API。仅持有标志不会损失任何性能。使用Python API时,Cython通常最快,但这是因为它执行的操作类型而不是持有标志(例如printf可能比Python print稍微快一点,但printf无论是否持有GIL都以相同的速度运行)。

你真正需要担心GIL的唯一时候是在使用多线程代码时,释放它可以让其他Python线程有机会运行。(同样,如果你正在编写一个库并且不需要Python API,释放GIL可能是个好主意,这样你的用户就可以运行其他线程了)。

最后,如果你在nogil块中并且想要进行快速的Python操作,你可以简单地使用以下代码:

with gil:
    print c

机会是,它不会对性能造成太大影响,并且可能节省大量编程工作。


这是一个类似于ChatGTP的答案 - user22213824
2
@HardikSindhav 我知道你因为我指出你大量发布ChatGPT答案而感到恼火。然而,这个答案比ChatGPT早约5年。 - DavidW
我不擅长写作,所以我使用ChatGPT。但是解决方案的代码是我自己编写的,我不使用ChatGPT。如果你不喜欢我的回答,那就不要阅读我的回答,但请停止给予负评。 - user22213824

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接