为啥即使使用 QThreadPool,GUI 也会冻结?
Posted
技术标签:
【中文标题】为啥即使使用 QThreadPool,GUI 也会冻结?【英文标题】:Why does the GUI freeze even with QThreadPool?为什么即使使用 QThreadPool,GUI 也会冻结? 【发布时间】:2017-05-27 21:59:25 【问题描述】:我正在尝试构建一个使用简单 QTextEdit 的自定义 Python 控制台小部件。行编辑框接收输入并通过线程中的 python 解释器运行它。
这里是interpreter.py
import sys
from io import StringIO, IncrementalNewlineDecoder
from code import InteractiveConsole
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
from stream import NewLineIO
class PythonInterpreter(QObject, InteractiveConsole):
output = pyqtSignal(str)
def __init__(self):
QObject.__init__(self)
self.l =
InteractiveConsole.__init__(self, self.l)
self.out = NewLineIO()
self.out.output.signal_str.connect(self.console)
def write(self, string):
self.output.emit(string)
def runcode(self, codez):
"""
Reimplementation to capture stdout and stderr
"""
sys.stdout = self.out
sys.stderr = self.out
sys.excepthook = sys.__excepthook__
result = InteractiveConsole.runcode(self, codez) # Where the magic happens
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
#self.output.emit(self.out.getvalue()) # Send the output
return result
@pyqtSlot(str)
def console(self, string):
#print(string, file=sys.__stdout__)
self.output.emit(string)
class javascriptInterpreter(QObject):
pass
这是 main.py
import sys
from traceback import TracebackException
from PyQt5 import QtCore, uic
from PyQt5.QtCore import QThread, QThreadPool
from PyQt5.QtGui import QFont, QColor
from PyQt5.QtWidgets import (QApplication, QDialog,
QAction)
from PyQt5.Qsci import QsciScintilla, QsciLexerPython, QsciAPIs
from interpreters import PythonInterpreter
from lexers import PythonLexer
from threads import Worker, WorkerSignals
from stream import NewLineIO
class MainWindow(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.ui = uic.loadUi("main.ui")
self.ui.showMaximized()
# Code Editor
self.font = QFont()
self.font.setFamily('Courier New')
self.font.setFixedPitch(True)
self.font.setPointSize(10)
self.ui.code_editor.setFont(self.font)
self.lexer = PythonLexer(self.ui, self.font)
self.lexer.lock()
# Console
self.interpreter = PythonInterpreter()
self.ui.console_log.isReadOnly()
self.ui.console_input.returnPressed.connect(self.send_console_input)
self.interpreter.output.connect(self.send_console_log)
# Threads
self.threadpool = QThreadPool()
def send_console_input(self):
command = self.ui.console_input.text()
self.ui.console_input.clear()
worker = Worker(self.interpreter.push, str(command))
worker.signals.result.connect(print)
worker.signals.finished.connect(self.thread_complete)
#self.interpreter.push(str(command))
self.threadpool.start(worker)
print("Thread Count: ",
self.threadpool.activeThreadCount(),
file=sys.__stdout__)
def thread_complete(self):
print("Thread Complete !")
def send_console_log(self, command):
print(command, file=sys.__stdout__)
self.ui.console_log.append(command)
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
每次发出来自PythonInterpreter
实例的信号时,它都会调用self.send_console_log
,后者接收在解释器上运行的命令的输出。
但是,如果我运行像for i in range(10000):print(i)
这样的大循环作为通过self.send_console_input
发送到解释器的命令,它将在self.send_console_log
中执行打印语句,但不是.append()
。它将冻结直到循环完成并且整个内容将附加到QTextEdit
。
如何解决这个问题?
【问题讨论】:
@ekhumoro 缺少什么?我会添加它。 【参考方案1】:我不确定,但如果 GUI 是主要部分,它必须在其他线程之前先启动。它可能发生在 GUI 之前开始的一些或一个胎面。看看这些
【讨论】:
GUI 首先启动。 main.py 中的self.ui.showMaximized()
行
如果数字大于一定数量,您是否尝试过拆分数字
它是一个解释器,所以它应该能够从一个线程中完成它。另外,拆分数字是什么意思?
假设你有 1000 个,这个 500 - 500 个。
添加try-除了附加部分,看看什么是错误。这样更有帮助以上是关于为啥即使使用 QThreadPool,GUI 也会冻结?的主要内容,如果未能解决你的问题,请参考以下文章
为啥即使使用单个 reducer 也会调用 Partitioner
Java:为啥即使路径完整,使用 file.exists() 也会给出错误值?