什么是Python中的导入锁?
我正在阅读《信号量小册子》,书中有一些代码可以让Python的语法和书里用的一样。不过,当我尝试导入他的代码时,出现了以下错误。
from threading_cleanup import *
RuntimeError: not holding the import lock
我知道这个错误和监视器函数的代码有关,因为如果我把它注释掉,错误就消失了。那段代码的作用是让我可以用键盘中断来结束程序。
有没有办法解决这个错误呢?
threading_cleanup.py
import threading
import time
import os
import signal
import sys
__all__ = ['Thread', 'Semaphore', 'watcher']
class Thread(threading.Thread):
def __init__(self, target, *args):
threading.Thread.__init__(self, target=target, args=args)
self.start()
class Semaphore(threading._Semaphore):
wait = threading._Semaphore.acquire
def signal(self, n=1):
for _ in range(n): self.release()
def value(self):
return self._Semaphore__value
def watcher():
child = os.fork()
if child == 0: return
try:
os.wait()
except KeyboardInterrupt:
print 'KeyboardInterrupt'
os.kill(child, signal.SIGKILL)
sys.exit()
watcher()
2 个回答
这个问题的标题在问什么是导入锁。
导入锁是Python在处理import
时的一部分,它会让程序在你违反一些不太明显的限制时出错。
你可以查看这个链接了解更多信息:https://docs.python.org/2/library/threading.html#importing-in-threaded-code
在你的例子中,因为你直接在模块里调用了watcher()
,所以除非这个模块是主模块,否则它不能启动线程。这里有个例子:
不过你的例子似乎有点不同,因为它涉及到进程。如果我把你的threading_cleanup.py
简化成:
import os
def watcher():
child = os.fork()
watcher()
我还是会遇到同样的错误:
File "main.py", line 1, in <module>
import threading_cleanup.py
RuntimeError: not holding the import lock
所以这可不是导入锁。虽然错误信息说这是导入锁,对吧?这听起来像是错误信息的一个bug。
在我的设置中,这个错误只在解释模式下出现。
看起来解释器不喜欢在还在导入模块的时候就进行分叉操作。
如果你去掉 watcher()
的调用,或者把它放在 if __name__ == '__main__':
这个条件语句里,错误就会消失。
一般来说,Python模块中执行的代码应该只用于初始化全局变量和单例对象。
哦!在导入之后,你可以从解释器中调用 threading_cleanup.watcher()
,这样就不会抛出异常了。
呃!我意识到我没有回答你问题的标题:
调用 fork()
会创建一个新的解释器进程;这个新进程需要导入模块才能开始执行。在解释模式下,你是在模块还在导入的过程中就让这个操作发生了,因此会出现锁定的情况。在解释模式下,交互式解释器是主程序。而在执行模式下,比如用 python mymodule.py
,模块就是主程序,所以它不会被 导入。这样说你明白了吗?