python 导入挂起

来源:互联网 发布:php数据采集器 编辑:程序博客网 时间:2024/06/05 02:28

在工作中遇到一个导入挂起的问题,花费了很长的时间才解决,

记录一下。

问题简单的复现如下:

a.py:

<span style="font-size:18px;">#coding: utf-8import datetimeimport b</span>
b.py:

#coding: utf-8import threadingimport sysdef test():    print 'before import datetime'    import datetime    print 'after import datetime' thd = threading.Thread(target=test)thd.start()print 'before b.join'thd.join()print 'after b.join'
单独执行python b.py是没有任何问题的,但是如果执行python a.py的话,

程序会停在thd.join()这段代码处。如果把test函数中的import datetime给

去掉的话,则python a.py也没有任何的问题。问题就出在import datetime

上。先看一下官网上怎么说的。

While the import machinery is thread-safe, there are two key restrictions 

on threaded imports due to inherent limitations in the way that thread-safety 

is provided:

   1.Firstly, other than in the main module, an import should not have the 
side effect of spawning a new thread and then waiting for that thread in any way. 
Failing to abide by this restriction can lead to a deadlock if the spawned thread 
directly or indirectly attempts to import a module.
链接是:https://docs.python.org/2/library/threading.html
我只摘录了导入挂起相关的部分。从官网解释的来看,主要是因为在import的
时候,使用了import mchinery,而且import mchinery是线程安全的。也就是
说,当有一个线程占用了import mchinery就相当于加锁了,如果其他的线程
想import,那么必须获取这个锁才行。现在回到我们的例子,在我们执行python 
a.py的时候执行到了import b,主线程获取了import mchinery的lock,那么继
续向下执行。在导入b的过程中,创建了另一线程C并且线程C中import了datetime
所以线程C尝试着去获取import mchinery的lock,而此时import mchinery的
lock被主线程拥有,并且还没有释放呢,所以线程C只能等import mchinery的
lock被释放,而此时主线程只有等到线程C结束之后,才能释放import mchinery
的lock,很显然,这里形成了死锁。所以导入执行到thd.join()时就因为死锁而挂起了。
解决的方法就是不要在新创建的线程中导入任何模块,把需要导入的模块在一开始就
导入进去。
还有一个值得奇怪的问题的是,为啥直接python b.py没有问题呢,这个也是在新创
建的线程中import的啊,个人认为主要是因为python b.py的时候,创建线程C的时候
没有任何线程在占用着import mchinery的lock,所以直接执行python b.py的时候,
线程C的导入不会形成死锁。

0 0
原创粉丝点击