如果未从主模块调用 wx.app.mainloop,则线程无法启动
thread fails to start if wx.app.mainloop isn't called from the main module
我希望有人能向我解释这种行为。如果我导入一个启动 wxpython 接口的模块,线程在 app.MainLoop() 结束之前无法启动。最简单的例子:
simple_app.py
import wx
from threading import Thread
def test():
from time import sleep
while 1:
print("thread still running")
sleep(2)
app = wx.App()
frame = wx.Frame(None, -1, 'simple.py')
frame.Show()
thread = Thread(target=test)
thread.setDaemon(True)
thread.start()
app.MainLoop()
main.py
import simple_app
如果你 运行 simple_app.py 本身它工作正常,如果你 运行 main.py 线程永远不会启动......为什么?我感觉这与线程无法获得锁有关。
这是一个很有趣的问题。手头的问题不是很明显(至少对我而言)。
simple_app.py 的最后一行阻塞直到 frame
是 closed/destroyed。因此,如果从 main.py 开始,导入将仅在框架关闭时完成(并显示打印输出)。
改为尝试以下方法(通常您会更好地构建程序以 start/stop 您需要的应用程序):
在 simple_app.py 中将最后一行更改为:
if __name__ == '__main__':
app.MainLoop()
在main.py
import wx
import simple_app
app = wx.GetApp()
app.MainLoop()
我不能告诉你为什么 运行 直接和导入有区别(运行 直接显示打印结果,而导入没有)。
simple_app.py
中的第二个线程正在尝试导入 time
模块,而导入已经 运行,这导致在从 simple_app
导入时出现死锁主模块。因为导入在导入模块时获取当前线程的解释器导入锁。已经 documented。
主模块中的线程可以导入其他模块,这就是 运行 simple_app.py
作为主模块工作的原因。将 from time import sleep
移动到 simple_app.py
中的模块级别可以解决问题。
运行下面的代码有助于更好地理解问题;
my_time.py
from time import sleep
simple_app.py
import imp
import sys
from threading import Thread
from time import sleep
import wx
class MyFinder(object):
def __init__(self):
print('MyFinder initializing')
if imp.lock_held():
while imp.lock_held():
print('import lock held')
sleep(2)
print('import lock released')
else:
print('import lock is not held')
def find_module(self, module, package=None):
print('MyFinder.find_module called with module name "{}", pakcage name "{}"'.format(module, package))
return None
def test():
sys.meta_path.append(MyFinder())
from my_time import sleep
count = 0
while True:
print("{} thread still running".format(count))
count += 1
sleep(2)
app = wx.App()
frame = wx.Frame(None, -1, 'simple.py')
frame.Show()
thread = Thread(target=test)
thread.setDaemon(True)
thread.start()
app.MainLoop()
我希望有人能向我解释这种行为。如果我导入一个启动 wxpython 接口的模块,线程在 app.MainLoop() 结束之前无法启动。最简单的例子:
simple_app.py
import wx
from threading import Thread
def test():
from time import sleep
while 1:
print("thread still running")
sleep(2)
app = wx.App()
frame = wx.Frame(None, -1, 'simple.py')
frame.Show()
thread = Thread(target=test)
thread.setDaemon(True)
thread.start()
app.MainLoop()
main.py
import simple_app
如果你 运行 simple_app.py 本身它工作正常,如果你 运行 main.py 线程永远不会启动......为什么?我感觉这与线程无法获得锁有关。
这是一个很有趣的问题。手头的问题不是很明显(至少对我而言)。
simple_app.py 的最后一行阻塞直到 frame
是 closed/destroyed。因此,如果从 main.py 开始,导入将仅在框架关闭时完成(并显示打印输出)。
改为尝试以下方法(通常您会更好地构建程序以 start/stop 您需要的应用程序):
在 simple_app.py 中将最后一行更改为:
if __name__ == '__main__':
app.MainLoop()
在main.py
import wx
import simple_app
app = wx.GetApp()
app.MainLoop()
我不能告诉你为什么 运行 直接和导入有区别(运行 直接显示打印结果,而导入没有)。
simple_app.py
中的第二个线程正在尝试导入 time
模块,而导入已经 运行,这导致在从 simple_app
导入时出现死锁主模块。因为导入在导入模块时获取当前线程的解释器导入锁。已经 documented。
主模块中的线程可以导入其他模块,这就是 运行 simple_app.py
作为主模块工作的原因。将 from time import sleep
移动到 simple_app.py
中的模块级别可以解决问题。
运行下面的代码有助于更好地理解问题;
my_time.py
from time import sleep
simple_app.py
import imp
import sys
from threading import Thread
from time import sleep
import wx
class MyFinder(object):
def __init__(self):
print('MyFinder initializing')
if imp.lock_held():
while imp.lock_held():
print('import lock held')
sleep(2)
print('import lock released')
else:
print('import lock is not held')
def find_module(self, module, package=None):
print('MyFinder.find_module called with module name "{}", pakcage name "{}"'.format(module, package))
return None
def test():
sys.meta_path.append(MyFinder())
from my_time import sleep
count = 0
while True:
print("{} thread still running".format(count))
count += 1
sleep(2)
app = wx.App()
frame = wx.Frame(None, -1, 'simple.py')
frame.Show()
thread = Thread(target=test)
thread.setDaemon(True)
thread.start()
app.MainLoop()