简体   繁体   English

使用并行性崩溃的程序:在没有 gil 的情况下不允许丢弃拥有的 Python 对象

[英]Program using parallelism crashing: Discarding owned Python object not allowed without gil

    %%cython
from threading import Thread
import time
def countdown(n):
    while n > 0:
        n -= 1

COUNT = 10000000


start = time.time()
t1 = Thread(target=countdown,args=(COUNT/2,))
t2 = Thread(target=countdown,args=(COUNT/2,))
with nogil:
    t1.start();t2.start()
    t1.join();t2.join()
    
end = time.time()
print(end-start)

I read on the Cython docs website that, almost every python code is workable in Cython.我在 Cython 文档网站上读到,几乎每个 python 代码都可以在 Cython 中使用。 As we know that is a famous snippet to demonstrate the limitations of Python and GIL.众所周知,这是一个著名的片段,用于演示 Python 和 GIL 的局限性。 I tried to recreate a solution in Cython.我试图在 Cython 中重新创建一个解决方案。

However, I am getting this issue in compiling this code.但是,我在编译这段代码时遇到了这个问题。

Error compiling Cython file:
------------------------------------------------------------
...

start = time.time()
t1 = Thread(target=countdown,args=(COUNT/2,))
t2 = Thread(target=countdown,args=(COUNT/2,))
with nogil:
    t1.start();t2.start()
           ^
------------------------------------------------------------

/Users/sanskar/.ipython/cython/_cython_magic_bb84bd2392afb02224d35c81782c007c.pyx:14:12: Discarding owned Python object not allowed without gil

Error compiling Cython file:
------------------------------------------------------------
...

I am fairly new to Cython, as evident from my code.从我的代码中可以明显看出,我对 Cython 相当陌生。 I would like to have some suggestions on how would I fix it.我想就如何修复它提出一些建议。

This is not going to work.这是行不通的。

The threading library returns Python objects.线程库返回 Python 对象。 To interact with them you need the GIL.要与他们互动,您需要GIL。 You therefore cannot expect to call .start() or .join() without the GIL.因此,您不能指望在没有 GIL 的情况下调用.start().join()

What's more useful is to wrap the parts of your function that don't need the GIL with a nogil block.更有用的是用 nogil 块包装不需要 GIL 的函数部分。 For example the loop in countdown could easily by done without the GIL (there's actually a good chance that the C compiler will spot that this loop is completely pointless and remove it completely, but that's a separate issue)例如, countdown的循环可以在没有 GIL 的情况下轻松完成(实际上,C 编译器很有可能会发现该循环完全没有意义并完全删除它,但这是一个单独的问题)

def countdown(int n):
    with nogil:
        while n > 0:
            n -= 1

This allows the majority of the work to be done without the GIL, but requires the GIL to be held at the start and end of the function.这允许在没有 GIL 的情况下完成大部分工作,但需要在函数的开始和结束时保持 GIL。


There's a secondary complication: regular Python code will release the GIL occasionally to allow other threads to run if needed.还有一个次要的复杂性:常规 Python 代码会偶尔释放 GIL,以允许其他线程在需要时运行。 Cython typically won't (although it might invoke Python code that does, so you can't rely on this). Cython 通常不会(尽管它可能会调用 Python 代码,因此您不能依赖于此)。 Therefore it probably makes sense to write countdown in Cython but not the code that starts the threads.因此,在 Cython 中编写countdown而不是启动线程的代码可能是有意义的。

I suspect this won't be an issue here but it's probably better to be safe.我怀疑这在这里​​不会成为问题,但安全起见可能更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM