依然是Python GIL 硬伤吗? 有人碰到C扩展的多线程问题吗?

少帮主 发布于 2012/12/28 10:13
阅读 4K+
收藏 0

开源之夏第三届火热来袭,高校学生参与赢万元奖金!>>>

写了个Python C扩展,用遍了三种实现方式:

  1. ctypes
  2. cython
  3. raw python c-api

碰到了经典的GIL全局locker问题(怀疑中),确定底层自己的C代码采用了线程安全


Python中单线程正常,Python多线程执行都出线莫名其妙的退出问题

如果是Python直接调用底层C的多线程routine,一切正常



以下是问题补充:

@少帮主:同样的C底层代码dll/so在java,C#,C/C++等其他平台下都采用各自平台多线程模式调用底层C routine(这部分代码也是我自己写的完全可控),全部正常在生产上跑很久了,代码贴出来也不好验证,发帖想看看是不是很多人遇到python封装C的类似问题 (2012/12/28 12:10)
加载中
1
用户名已存在
用户名已存在

python线程是源生线程,windows下可以用工具查看得到,python c在windows下调用_beginthread函数(Linux 下调用 pthread api)来创建新线程。python的线程调度最终实际上仍然是由系统来完成。只不过由于gil的存在,python线程在获得许可执行之后,要先去请求 interpreter资源,当看到interpreter目前被锁,会继续进入睡眠状态,等待下一次唤醒。一般python线程大概执行100条python字节指令就会释放interpreter资源(仅限多线程环境下,即import 过threading或_thread模块)。


楼主的问题,我觉得是c扩展开了新线程,然后这些线程其实是不被GIL限制的。没有做好c扩展新开线程和python线程的线程安全问题。

少帮主
少帮主
谢谢,C扩展开辟新线程来处理一切都正常的,不受python控制,但是如果在python中开辟线程调用C的任务就出错了,你说的windows版本有时候是不莫名其妙退出的,但是linux下非常确定的无任何反应的退出,debug都退出
0
ChenQi
ChenQi
python mailing list上问一问吧。附上自己的简单代码结构。
0
少帮主
少帮主

引用来自“ChenQi”的答案

python mailing list上问一问吧。附上自己的简单代码结构。
基本上都看过了,stackoverflow,mailing list,google group,一般都不在这里问问题,只想知道OSC有没有人遇到类似的问题,真正能解决问题的当然还是stackoverflow
0
用户名已存在
用户名已存在

没代码一切白搭。

异常退出?c扩展有开新的线程?你是把线程的调度管理交付给python(依赖系统),还是直接依赖系统?


0
少帮主
少帮主

引用来自“用户名已存在”的答案

没代码一切白搭。

异常退出?c扩展有开新的线程?你是把线程的调度管理交付给python(依赖系统),还是直接依赖系统?


无异常结束,coredump没有,多线程执行都不成功,用python的线程来处理出问题,交给C无问题,代码相对多,没办法贴,用最简单的c试过,同样出问题,谢谢
0
南湖船老大
南湖船老大
不懂python。但是python教材中(一本很经典的书)是确实说过python的多线程是假多线程。
0
sam_ai
sam_ai
别想了,只要你还在Python虚拟机那个层面,你都是不能移除GIL的。首先要明白啥叫GIL,为啥要设计GIL。这个呢,Python的作者认为需要在某种不大不小的粒度上加锁(他任务太小粒度的锁会降低效率),所以就有了GIL。GIL的历史非常悠久,至今仍旧存在。
0
sam_ai
sam_ai

我曾经想用OpenMP去对付GIL(不是用Cython那种方式,Cython其实是自动生成的C扩展):我用的是Python2.5...

但是不管我用C去控制Python虚拟机(C 可以用OpenMP)还是用Python多线程去调用C,结果都是一样的:无效...

第一种直接非法操作... 第二种GIL继续发挥作用...

用户名已存在
用户名已存在
回复 @少帮主 : 按照这个描述,就想不出哪里出问题了。其实python的多线程实现,线程调度api非常简陋,而且用python做多线程对于效率来说没意义。 或者你可以把python部分的代码简化贴出来看看。
少帮主
少帮主
回复 @用户名已存在 : 确实单独在C开辟线程没有,做的同一份c代码在java,C#下都全部正常运行了,java和C#这两个平台都在各自平台上实现多线程而不是在c底层多线程,所有代码都我自己写的,在生产上跑很久了,扩展到pyton上出了这个棘手的问题
用户名已存在
用户名已存在
你可以通过c扩展,在扩展里面新开一个线程B,然后在新线程B中调用OpenMP API去做并行计算。这个线程B是不受GIL约束的。当然你可以额外添加以下锁机制。 而且CPython的意思就是 python的c实现,用的很多(普遍概念的2.x 3.x都是这么指)。C# java实现不是这么叫。
0
sam_ai
sam_ai

引用来自“sam_ai”的答案

我曾经想用OpenMP去对付GIL(不是用Cython那种方式,Cython其实是自动生成的C扩展):我用的是Python2.5...

但是不管我用C去控制Python虚拟机(C 可以用OpenMP)还是用Python多线程去调用C,结果都是一样的:无效...

第一种直接非法操作... 第二种GIL继续发挥作用...

可不是么,现在要用多线程只能这么做....(Cython也是这么搞的)

但是这样Python的作用更低了...我很多时候干脆直接用C了。

0
少帮主
少帮主

引用来自“sam_ai”的答案

引用来自“sam_ai”的答案

我曾经想用OpenMP去对付GIL(不是用Cython那种方式,Cython其实是自动生成的C扩展):我用的是Python2.5...

但是不管我用C去控制Python虚拟机(C 可以用OpenMP)还是用Python多线程去调用C,结果都是一样的:无效...

第一种直接非法操作... 第二种GIL继续发挥作用...

可不是么,现在要用多线程只能这么做....(Cython也是这么搞的)

但是这样Python的作用更低了...我很多时候干脆直接用C了。

是不是我们都没有注意到某些trick导致的啊


cdef extern from "Python.h":
    cdef void PyEval_InitThreads()

# It seems that in only *some* version of Python/Cython we need to call this
# by hand to get threads initialized. Not clear why this is the case though.
# If we don't have this, pyzmq will segfault.
def init_threads():
    PyEval_InitThreads()

__all__ = ['init_threads']


摘自pyzmq项目中的线程处理细节,pyzmq多线程没出问题,我直接在python C-api中调用了依然无效, 

PyEval_InitThreads


用户名已存在
用户名已存在
cpython的实现,默认认为用户使用都是单进程单线程,为了提高速度,默认是不初始化多线程环境的。只有当import thread模块或者显示调用api才会初始化。
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部
返回顶部
顶部