线程实时记录

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,所以简单的解决方案真的没问题。

以上是关于线程实时记录的主要内容,如果未能解决你的问题,请参考以下文章

C# 多线程 大量数据实时接收\解析\存储 问题

界面实时刷新线程信息

如何在实时应用程序中锁定线程[关闭]

实时音频编程:实践与技巧

python分别使用多线程和多进程获取所有股票实时数据

Opencv/c++ - 在线程中录制实时视频,在另一个线程中处理图像?