我使用线程锁编写了一个简单的测试程序。该程序的行为不符合预期,python解释器不会抱怨。
test1.py:
from __future__ import with_statement
from threading import Thread, RLock
import time
import test2
lock = RLock()
class Test1(object):
def __init__(self):
print("Start Test1")
self.test2 = test2.Test2()
self.__Thread = Thread(target=self.myThread, name="thread")
self.__Thread.daemon = True
self.__Thread.start()
self.test1Method()
def test1Method(self):
print("start test1Method")
with lock:
print("entered test1Method")
time.sleep(5)
print("end test1Method")
def myThread(self):
self.test2.test2Method()
if __name__ == "__main__":
client = Test1()
raw_input()
test2.py:
from __future__ import with_statement
import time
import test1
lock = test1.lock
class Test2(object):
def __init__(self):
print("Start Test2")
def test2Method(self):
print("start test2Method")
with lock:
print("entered test2Method")
time.sleep(5)
print("end test2Method")
两个睡眠都在同一时间执行!不是我在使用锁时的预期。
当test2Method移动到test1.py时,一切正常。当我在test2.py中创建锁并将其导入test1.py时,一切正常。当我在一个单独的源文件中创建锁并在test1.py和test2.py中导入它时,一切正常。
可能它与circulair进口有关。
但为什么python不抱怨这个?
答案 0 :(得分:3)
在Python中使用$ python test1.py
执行python脚本时,您的test1.py
将被导入为__main__
而不是test1
,所以如果你想获得在启动的脚本中定义的锁不应该import test1
,但是您应该import __main__
,因为如果您执行第一个锁定,则会创建另一个与__main__.lock
不同的锁({1} }})。
因此,您可以解决问题(远远不是最好的)和查看正在发生的事情,您可以将2脚本更改为:
test1.py:
test1.lock != __main__.lock
test2.py:
from __future__ import with_statement
from threading import Thread, RLock
import time
lock = RLock()
class Test1(object):
def __init__(self):
print("Start Test1")
import test2 # <<<<<<<<<<<<<<<<<<<<<<<< Import is done here to be able to refer to __main__.lock.
self.test2 = test2.Test2()
self.__Thread = Thread(target=self.myThread, name="thread")
self.__Thread.daemon = True
self.__Thread.start()
self.test1Method()
def test1Method(self):
print("start test1Method")
with lock:
print("entered test1Method")
time.sleep(5)
print("end test1Method")
def myThread(self):
self.test2.test2Method()
if __name__ == "__main__":
client = Test1()
raw_input()
HTH,
答案 1 :(得分:1)
在print
语句之前和之后使用import
语句并在创建后立即打印id(lock)
表明实际上已创建了两个锁。似乎模块被导入了两次,并且mouad在他的回答中解释说这是因为test1.py
首先导入__main__
然后导入test1
,这导致锁被实例化两次。
尽管如此,使用全局锁定无论如何都不是一个好的解决方案。有几种更好的解决方案,我认为你会发现其中一种能满足你的需求。
将锁实例化为Test1
的类变量,并将其作为参数传递给Test2
将锁实例化为Test1
中__init__
的正常变量,并将其作为参数传递给Test2
。
在if __name__ == "__main__"
块中实例化锁定并将其传递给Test1
,然后从Test1
传递到Test2
。
在if __name__ == "__main__"
块中实例化锁定并首先使用锁定实例化Test2
,然后将Test2
实例和锁定传递给{ {1}}。 (这是这种做法最脱钩的方式,我建议采用这种方法。至少可以简化单元测试。)。
以下是最后一条建议的代码:
Test1
test1.py
class Test1(object):
def __init__(self, lock, test2):
print("Start Test1")
self.lock = lock
self.test2 = test2
self.__Thread = Thread(target=self.myThread, name="thread")
self.__Thread.daemon = True
self.__Thread.start()
self.test1Method()
def test1Method(self):
print("start test1Method")
with self.lock:
print("entered test1Method")
time.sleep(1)
print("end test1Method")
def myThread(self):
self.test2.test2Method()
if __name__ == "__main__":
lock = RLock()
test2 = test2.Test2(lock)
client = Test1(lock, test2)
test2.py
答案 2 :(得分:0)
正如其他人所说,问题不在于threading
,而是在你的循环导入的特殊情况下。
为什么特别?因为通常的工作流程(mod1
导入mod2
和mod2
导入mod1
)看起来像下一个:
您想使用模块mod1,导入它(import mod1
)
当Python找到它时,解释器将其添加到sys.modules
并开始执行代码
当它与import mod2
对齐时,会停止执行mod1
并开始执行mod2
当解释程序在import mod1
内到达mod2
时,不加载mod1
,因为它已添加到sys.modules
< / p>
之后(除非mod2
中的某些代码访问mod1
中的某些未初始化资源)解释程序完成mod2
和mod1
的执行。
但是在第4步的情况下,Python再次执行test1
,因为test1
中没有sys.modules
!原因是您没有首先导入它,而是从命令行运行它。
所以,只是不要使用循环导入 - 因为你看它真是一团糟。