Python 使用线程回调时解释器崩溃
Python interpreter crashes when using callback from thread
我用 pyqt5 写了一个 Gui-App。
我用threading.Thread创建了一个Thread,它做一些计算。
该线程获取名称、目标、args、kwargs 和一个回调函数,它是我的应用程序 class.
的成员
除最后一次 运行 外,回调有效多次。
例如,100 次呼叫中的前 99 次执行良好,但没有。 100 导致错误。
上次从回调返回后,解释器在大约一秒后崩溃并出现 Windows 事件,事件代码 0xc0000005
回调也有 **kwargs 作为参数
python 本身没有回溯。
任何人都知道可能是什么原因或我做错了什么?
环境:
- Windows10,
- Python3.9.0,
- PyQt5 5.15.1
两个 classes 的最小示例(可能不起作用):
from Controller.filecontroller import Files_Controller as filecontroller
class DialogBatch(QDialog):
def __init__(self, parent= None):
# Initialize super-class
super(DialogBatch, self).__init__()
# Load the GUI Description File, created with QtDesigner
uic.loadUi('.\GUI_dialog_batch_ui\dialog_batch.ui', self)
# QProgressBars
self.progressBar_batch_progress = self.findChild(QProgressBar, 'progressBar_batch_progress')
# QPushButtons
self.pushButton_batch_start = self.findChild(QPushButton, 'pushButton_batch_start')
....
# Filecontroller for file-operations
self.filecontroller = filecontroller()
# Thread for executing high-level batch operations;
self.__batchthread = None
# Show GUI
self.show()
....
# Callback
def __update_GUI(self, **kwargs):
"""! Hidden method for updating the GUI
@param key-only progress: [int] progress of the task executed
@return: [int] 1 after finishing
"""
test = deepcopy(kwargs)
print("Callback entered")
if "progress" in test:
self.progressBar_batch_progress.setValue(test["progress"])
print("__update_GUI: Callback called!")
else:
print("__update_GUI: No Parameter!")
print("update GUI finished")
return 1
....
def slot_pushbutton_start_clicked(self):
...
self.__batchthread = threading.Thread(\
name='Batchthread', \
target=self.filecontroller.batch_folder,\
args=(self.input[0], self.signals[0], self.databases),\
kwargs={"callback":self.__update_GUI})
self.__batchthread.start()
...
class Files_Controller(object):
## Constructor
# @param self
def __init__(self):
...
self.__killbatchthread = False
self._func_callback = None
...
...
def batch_folder(self, files, signals, databases, *args, **kwargs):
...
self.__params = {}
files_read = 0
files_painted = 0
progress = 0
...
for each_file in allfiles:
...
....
files_read +=1
# Cancel
if self.get_killbatchthreat(): return -1
# Callback for Update
if self._func_callback is not None:
progress = int((files_read+files_painted)*50/number_of_files)
self.__params.clear()
self.__params={"progress":progress}
self._func_callback(**self.__params)
...
files_painted +=1
# Callback for GUI update
if self._func_callback is not None:
progress = int((files_read+files_painted)*50/number_of_files)
self.__params.clear()
self.__params={"progress":progress}
print("Returnvalue: %i" %(self._func_callback(**self.__params)))
for i in range(10):
print("Sleeptime: %i" %i)
time.sleep(1)
....
最后一次使用最后一个文件调用 _func_callback 时产生了这个输出:
回调输入
__update_GUI: 回调已调用!
更新界面完成
返回值:1
睡眠时间:0
睡眠时间:1
睡眠时间后:1
python 解释器崩溃。
我可以自己解决:
随着设计的改变,问题消失了。
问题是使用来自非 w-gui-thread-function 的回调到 gui class(在 gui 线程中)。
使用信号而不是回调后,它工作正常。
结论:
切勿从 none-gui-thread 函数调用 gui-thread-function。
我用 pyqt5 写了一个 Gui-App。
我用threading.Thread创建了一个Thread,它做一些计算。 该线程获取名称、目标、args、kwargs 和一个回调函数,它是我的应用程序 class.
的成员除最后一次 运行 外,回调有效多次。 例如,100 次呼叫中的前 99 次执行良好,但没有。 100 导致错误。 上次从回调返回后,解释器在大约一秒后崩溃并出现 Windows 事件,事件代码 0xc0000005
回调也有 **kwargs 作为参数
python 本身没有回溯。
任何人都知道可能是什么原因或我做错了什么?
环境:
- Windows10,
- Python3.9.0,
- PyQt5 5.15.1
两个 classes 的最小示例(可能不起作用):
from Controller.filecontroller import Files_Controller as filecontroller
class DialogBatch(QDialog):
def __init__(self, parent= None):
# Initialize super-class
super(DialogBatch, self).__init__()
# Load the GUI Description File, created with QtDesigner
uic.loadUi('.\GUI_dialog_batch_ui\dialog_batch.ui', self)
# QProgressBars
self.progressBar_batch_progress = self.findChild(QProgressBar, 'progressBar_batch_progress')
# QPushButtons
self.pushButton_batch_start = self.findChild(QPushButton, 'pushButton_batch_start')
....
# Filecontroller for file-operations
self.filecontroller = filecontroller()
# Thread for executing high-level batch operations;
self.__batchthread = None
# Show GUI
self.show()
....
# Callback
def __update_GUI(self, **kwargs):
"""! Hidden method for updating the GUI
@param key-only progress: [int] progress of the task executed
@return: [int] 1 after finishing
"""
test = deepcopy(kwargs)
print("Callback entered")
if "progress" in test:
self.progressBar_batch_progress.setValue(test["progress"])
print("__update_GUI: Callback called!")
else:
print("__update_GUI: No Parameter!")
print("update GUI finished")
return 1
....
def slot_pushbutton_start_clicked(self):
...
self.__batchthread = threading.Thread(\
name='Batchthread', \
target=self.filecontroller.batch_folder,\
args=(self.input[0], self.signals[0], self.databases),\
kwargs={"callback":self.__update_GUI})
self.__batchthread.start()
...
class Files_Controller(object):
## Constructor
# @param self
def __init__(self):
...
self.__killbatchthread = False
self._func_callback = None
...
...
def batch_folder(self, files, signals, databases, *args, **kwargs):
...
self.__params = {}
files_read = 0
files_painted = 0
progress = 0
...
for each_file in allfiles:
...
....
files_read +=1
# Cancel
if self.get_killbatchthreat(): return -1
# Callback for Update
if self._func_callback is not None:
progress = int((files_read+files_painted)*50/number_of_files)
self.__params.clear()
self.__params={"progress":progress}
self._func_callback(**self.__params)
...
files_painted +=1
# Callback for GUI update
if self._func_callback is not None:
progress = int((files_read+files_painted)*50/number_of_files)
self.__params.clear()
self.__params={"progress":progress}
print("Returnvalue: %i" %(self._func_callback(**self.__params)))
for i in range(10):
print("Sleeptime: %i" %i)
time.sleep(1)
....
最后一次使用最后一个文件调用 _func_callback 时产生了这个输出:
回调输入 __update_GUI: 回调已调用! 更新界面完成 返回值:1 睡眠时间:0 睡眠时间:1
睡眠时间后:1 python 解释器崩溃。
我可以自己解决: 随着设计的改变,问题消失了。
问题是使用来自非 w-gui-thread-function 的回调到 gui class(在 gui 线程中)。 使用信号而不是回调后,它工作正常。
结论: 切勿从 none-gui-thread 函数调用 gui-thread-function。