线程实时记录
Posted
技术标签:
【中文标题】线程实时记录【英文标题】:Threads real-time logging 【发布时间】:2017-03-27 07:20:28 【问题描述】:我正在编写一个用于调整照片大小的简单脚本。我想要一个带有文本字段的小部件,在调整每个文件大小后会在其中显示消息。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import time, sys
from PyQt5.QtCore import pyqtSignal, QThread
from PyQt5.QtWidgets import QApplication, QPushButton, QTextEdit, QWidget, QVBoxLayout
class Thread(QThread):
log = pyqtSignal(str)
def __init__(self, parent=None):
super(Thread, self).__init__(parent)
def test(self, i):
time.sleep(1)
self.log.emit(str(i))
class Widget(QWidget):
def __init__(self):
super().__init__()
self.ui()
def process(self):
self.toLog('some text...')
worker = Thread()
worker.log.connect(self.toLog)
for i in range(1, 5):
worker.test(i)
def ui(self):
self.LogOutputTxt = QTextEdit()
self.LogOutputTxt.setReadOnly(True)
startBtn = QPushButton('Start')
startBtn.clicked.connect(self.start)
layout = QVBoxLayout()
layout.addWidget(self.LogOutputTxt)
layout.addWidget(startBtn)
self.setLayout(layout)
self.resize(400, 300)
self.show()
def start(self):
self.toLog('start')
self.process()
def toLog(self, txt):
self.LogOutputTxt.append(txt)
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = Widget()
sys.exit(app.exec_())
到目前为止,在调整所有文件大小后,所有消息都会立即显示。有没有办法一一做到(我的意思是文件大小调整、消息显示等)?
【问题讨论】:
您发布的代码不完整,而且在很多方面都存在错误,因此很难有建设性地重新编写它。请阅读有关如何生成minimal reproducible example 的指南。 对不起,我重写了代码,希望现在更好。 您是否希望这些工作线程同时运行?如果他们正在执行受 cpu 限制的 python 代码(例如调整图像大小),则一次只能运行其中一个(因为全局解释器锁)。对于并行处理,您需要使用单独的进程,而不是线程。 不完全是 - 我的意图是在每次调整图像大小后都会更新 GUI。现在看起来首先调整了图像的大小,然后更新了 GUI。就像上面的代码一样——我希望每次睡眠后我都会收到一条消息到 LogOutputTxt。 【参考方案1】:下面是对你的脚本的重写,应该是你想要的。
但请注意,这非常简单,并且不会太努力地确保线程安全。 setItems
方法只是制作传递给它的数据的浅表副本 - 这仅适用于不可变对象列表。您还必须确保您永远不会在工作线程中执行任何 gui 操作,其中包括对像素图的操作。如果要处理图像,请使用QImage
。 (如果您想知道如何停止正在运行的线程,请参阅例如this answer)。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import time, sys
from PyQt5.QtCore import pyqtSignal, QThread
from PyQt5.QtWidgets import (
QApplication, QPushButton, QTextEdit, QWidget, QVBoxLayout
)
class Thread(QThread):
log = pyqtSignal(str)
def __init__(self, parent=None):
super(Thread, self).__init__(parent)
self._items = []
def setItems(self, items):
if not self.isRunning():
self._items[:] = items
def run(self):
for item in self._items:
time.sleep(1)
self.log.emit('processing: %s' % item)
class Widget(QWidget):
def __init__(self):
super().__init__()
self.ui()
self._worker = Thread(self)
self._worker.log.connect(self.toLog)
self._worker.started.connect(lambda: self.toLog('start'))
self._worker.finished.connect(lambda: self.toLog('finished'))
def process(self):
items = ['Image%02d.png' % i for i in range(10)]
self._worker.setItems(items)
self._worker.start()
def ui(self):
self.LogOutputTxt = QTextEdit()
self.LogOutputTxt.setReadOnly(True)
startBtn = QPushButton('Start')
startBtn.clicked.connect(self.start)
layout = QVBoxLayout()
layout.addWidget(self.LogOutputTxt)
layout.addWidget(startBtn)
self.setLayout(layout)
self.resize(400, 300)
self.show()
def start(self):
if not self._worker.isRunning():
self.process()
def toLog(self, txt):
self.LogOutputTxt.append(txt)
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = Widget()
sys.exit(app.exec_())
【讨论】:
感谢您的回复 :-)。对我来说似乎已经足够了。一开始我使用 PIL 编写了简单的命令批处理脚本进行图像处理,我只是出于好奇尝试创建 GUI,所以简单的解决方案真的没问题。以上是关于线程实时记录的主要内容,如果未能解决你的问题,请参考以下文章