Python C API-线程安全吗? [英] Python C API - Is it thread safe?

查看:109
本文介绍了Python C API-线程安全吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C扩展名,该扩展名是从我的多线程Python应用程序中调用的.我在C函数中的某个地方使用了静态变量i,稍后还会有一些i++语句可以从不同的Python线程运行(尽管该变量仅在我的C代码中使用,但我不会产生到Python).

I have a C extension that is called from my multithreaded Python application. I use a static variable i somewhere in a C function, and I have a few i++ statements later on that can be run from different Python threads (that variable is only used in my C code though, I don't yield it to Python).

由于某种原因,到目前为止我还没有满足任何比赛条件,但是我想知道这是否很幸运...

For some reason I haven't met any race condition so far, but I wonder if it's just luck...

我没有任何与线程相关的C代码(没有Py_BEGIN_ALLOW_THREADS或任何东西).

I don't have any thread-related C code (no Py_BEGIN_ALLOW_THREADS or anything).

我知道GIL仅保证单个字节码指令是原子性的和线程安全的,因此Python中的i+=1语句不是线程安全的.

I know that the GIL only guarantees single bytecode instructions to be atomic and thread-safe, thus statements as i+=1 in Python are not thread-safe.

但是我不知道C扩展中的i++指令.有帮助吗?

But I don't know about a i++ instruction in a C extension. Any help ?

推荐答案

在运行C代码时,Python不会释放GIL(除非您告知它).它仅在字节码指令之前(而不是在此期间)释放GIL,并且从解释器的角度来看,运行C函数是执行CALL_FUNCTION字节码的一部分.* (不幸的是,我找不到引用对于本段,但我几乎可以肯定是对的)

Python will not release the GIL when you are running C code (unless you tell it to). It only releases the GIL just before a bytecode instruction (not during) and from the interpreter's point of view running a C function is part of executing the CALL_FUNCTION bytecode.* (Unfortunately I can't find a reference for this paragraph currently, but I'm almost certain it's right)

因此,除非您进行任何特定的操作,否则C代码将是唯一正在运行的线程,因此您在其中执行的任何操作都应该是线程安全的.

Therefore, unless you do anything specific your C code will be the only thread running and thus any operation you do in it should be thread safe.

如果您特别想发布GIL-例如,因为您要进行长时间的计算而不会干扰Python,从文件读取或在等待其他事情发生时休眠-那么最简单的方法是做 Py_BEGIN_ALLOW_THREADS然后Py_END_ALLOW_THREADS当您想找回它时.在这段代码中,您不能使用大多数Python API函数,并且有责任确保C语言中的线程安全.最简单的方法是仅使用局部变量,而不读取或写入任何全局状态.

If you specifically want to release the GIL - for example because you're doing a long calculation which doesn't interfere with Python, reading from a file, or sleeping while waiting for something else to happen - then the easiest way is to do Py_BEGIN_ALLOW_THREADS then Py_END_ALLOW_THREADS when you want to get it back. During this block you cannot use most Python API functions and it's your responsibility to ensure thread safety in C. The easiest way to do this is to only use local variables and not read or write any global state.

如果您已经在没有GIL(线程A)的情况下运行了C线程,那么仅将GIL保持在线程B中就不能保证线程A不会修改C全局变量.为了安全起见,您需要确保在所有C函数中都没有某种锁定机制(Python GIL或C机制)的情况下,永远不要修改全局状态.

If you've already got a C thread running without the GIL (thread A) then simply holding the GIL in thread B does not guarantee that thread A won't modify C global variables. To be safe you need to ensure that you never modify global state without some kind of locking mechanism (either the Python GIL or a C mechanism) in all your C functions.

其他思想

*可以用C代码发布GIL的地方之一是,如果C代码调用了导致执行Python代码的操作.这可能是通过使用PyObject_Call来完成的.如果Py_DECREF导致要执行析构函数,则不太明显.您可以在恢复C代码时恢复GIL,但是您不能再保证全局对象不变.这种明显的影响不会影响像x++这样的简单C.

* One place where the GIL can be released in C code is if the C code calls something that causes Python code to be executed. This might be through using PyObject_Call. A less obvious place would be if Py_DECREF caused a destructor to be executed. You'd have the GIL back by the time your C code resumed, but you could no longer guarantee that global objects were unchanged. This obvious doesn't affect simple C like x++.

这篇关于Python C API-线程安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆