关于如何实例化和使用qthread
的官方文档可以在以下位置找到:http://doc.qt.io/qt-5/qthread.html
文档描述了两种基本方法:(1)worker-object方法和(2)QThread
子类方法。
我在几篇文章中读到第二种方法不好,所以让我们集中讨论第一种方法。
编辑:
@ekhumoro给我指出了下面这篇有趣的文章:https://woboq.com/blog/qthread-you-were-noth-down-so-wurn.html。显然,这两种方法(1)和(2)各有其优点:
由于我确实需要在QApplication线程和新的QThread之间进行某种通信(我相信signal-slot是一种很好的通信方式),所以我将使用Worker-Object方法。
我已经复制粘贴了Worker-Object方法的C++代码(来自官方的Qt5文档,请参见http://doc.qt.io/qt-5/qthread.html):
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Worker(QObject):
resultReady = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@pyqtSlot(str)
def doWork(self, param):
result = "hello world"
print("foo bar")
# ...here is the expensive or blocking operation... #
self.resultReady.emit(result)
class Controller(QObject):
operate = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 1. Create 'workerThread' and 'worker' objects
# ----------------------------------------------
self.workerThread = QThread()
self.worker = Worker() # <- SEE NOTE(1)
self.worker.moveToThread(self.workerThread)
# 2. Connect all relevant signals
# --------------------------------
self.workerThread.finished.connect(self.worker.deleteLater)
self.workerThread.finished.connect(lambda: print("workerThread finished.")) # <- SEE NOTE(2)
self.operate.connect(self.worker.doWork)
self.worker.resultReady.connect(self.handleResults)
# 3. Start the thread
# --------------------
self.workerThread.start()
def __del__(self):
self.workerThread.quit()
self.workerThread.wait()
@pyqtSlot(str)
def handleResults(self, param):
print(param)
# One way to end application
# ---------------------------
# global app # <- SEE
# app.exit() # NOTE(3)
# Another way to end application
# -------------------------------
self.workerThread.quit() # <- SEE NOTE(4)
self.thread().quit()
if __name__ == '__main__':
app = QCoreApplication([])
controller = Controller()
controller.operate.emit("foo") # <- SEE NOTE(5)
sys.exit(app.exec_())
注意(1):
最初我将worker
变量实现为构造函数中的局部变量。我正在将C++示例翻译成Python,这个变量也是C++示例中的一个局部变量。
正如您在@pschill的注释中看到的,这个局部变量被垃圾收集,因此我无法让线程运行。在进行更改之后,我得到了预期的输出。
注意(2):
我添加这一行是为了准确地知道WorkerThread
何时完成。
注意(3):
显然,我需要将这两个代码global app
和app.exit()
添加到handleresults(..)
插槽中。谢谢@matic指出这一点!
注意(4):
我(通过一些文档)发现了这种结束应用程序的方法。第一个codeline结束WorkerThread
(通过终止其事件循环)。第二个codeline结束mainthread
(也通过终止其事件循环)。
注意(5):
在Windows控制台中运行代码时,什么也没有发生(它只是挂起)。根据@pschill的建议(见下面他的评论),我添加了这个codeline以确保调用dowork()
函数。
将代码全局应用程序
和app.exit()
添加到handleResults(..)
插槽可以修复挂起问题。但是背景到底发生了什么呢?这些代码是在扼杀工人线程吗?还是主QApplication线程?
有没有一种方法可以在不杀死主QApplication线程的情况下杀死辅助线程?
1.仍然不确定…
@pyqtSlot(str)
def handleResults(self, param):
print(param)
self.workerThread.quit() # Kill the worker thread
self.thread().quit() # Kill the main thread
self.workerThread.finished.connect(lambda: print("workerThread finished."))
我确实像预期的那样把行打印出来了。我还尝试以类似的方式检查主线程的杀死:
self.thread().finished.connect(lambda: print("mainThread finished."))
不幸的是,这行不能打印出来。为什么?
特此提供我当前的系统设置:
、 、 、 > Qt5(QT_version_str
=5.10.1)
> PyQt5(pyqt_version_str
=5.10.1)
> Python 3.6.3
· · · > Windows 10,64位
您的Python示例应用程序需要以某种方式退出,否则它只是在控制器
对象初始化后就坐在那里。
最简单的方法是将示例中的handleResults
函数更改为:
@pyqtSlot(str)
def handleResults(self, param):
print(param)
global app
app.exit()
希望能有所帮助。
etcd 是一个分布式键值对存储,设计用来可靠而快速的保存关键数据并提供访问。通过分布式锁,leader选举和写屏障(write barriers)来开启可靠的分布式协同。etcd集群是为高可用,持久性数据存储和检索而准备。 开始 现在etcd的用户和开发者可以从 下载并构建 etcd开始。在获取etcd之后,跟随 quick demo 来看构建和操作etcd集群的基本内容。 使用etcd开发 开
内容 Why etcd (TODO) 理解数据模型 理解API 术语 API保证 Internals (TODO) 额外说明 这些内容主要是介绍 etcd 的概念和实现细节,适合希望深入了解 etcd 的同学。 内容来自 github 官网,地址: https://github.com/coreos/etcd/tree/master/Documentation/learning
内容 开发指南的内容如下: 搭建本地集群 和 etcd 交互 gRPC etcd core 和 etcd concurrency API 参考 经过gRPC 网关的 HTTP JSON API gRPC命名与发现 客户端 和 代理 命名空间 内嵌的 etcd 试验性的 API 和特性 系统限制 注: 内容来自 https://github.com/coreos/etcd/tree/master/D
内容 搭建etcd集群 搭建etcd网关 在容器内运行etcd集群 配置 加密(TODO) Monitoring 维护 理解失败 灾难恢复 性能 版本 支持平台 额外说明 这些内容相当于是 etcd3 的管理手册,针对的是 etcd3 的管理者(如运维人员)。对于运维人员,需要重点阅读这些内容。 内容来自 github 官网,地址: https://github.com/coreos/etcd/t
问题内容: 我在Django 1.6上无法正常使用翻译存在问题。我已将此添加到我的settings.py中: 还添加了中间件: 以及每当我使用应为l10nd的字符串时的* .py文件: 我的模板开始于: 在模板内部,我使用了trans占位符。例如 我在locale / de / LC_MESSAGES / django.po中提供了翻译: 问题答案: 添加到并将其设置如下: 请注意,它必须是一个元
Selenium Python bindings 提供了一个简单的 API,让你使用 Selenium WebDriver 来编写功能/校验测试。 通过 Selenium Python 的 API,你可以非常直观的使用 Selenium WebDriver 的所有功能。