技术标签: Python多线程 python pyqt 多线程
我是一个Python初学者,最近在用PyQt5做Gui的时候遇到一个烧脑的问题,如何安全的实现线程的暂停、终止。如果粗暴的kill掉线程,比如说线程正在requests一个数据,这样总感觉不太好,于是查阅了1晚上的各种资料(没有老师教,没地请教,只能自己动手~呜呜呜呜)。
线程一般用在网络连接、释放系统资源、dump流文件,这些都跟IO相关了,你突然关闭线程那这些
没有合理地关闭怎么办?是不是就是给自己造bug呢?
经过各种资料的查询,有使用TerminateThread强行终止线程的,有使用thread.join阻塞线程的(原来我还不是特别明白),经过思考我想到了一直不借助任何其他库,用基本函数就可以实现的线程挂起、终止的办法。
简单来说,就是定义个线程stop状态的全局变量,每次线程循环的时候就检查一下这个变量是不是提示自己该停止或者暂停或者恢复了,而且不强行终止线程,还可以重新开启。废话不多说,直接上代码:
# An highlighted block
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
import time
class Worker(QThread):
valueChanged = pyqtSignal(int) # 值变化信号
status = pyqtSignal(int)
def run(self):
print('thread id', int(QThread.currentThreadId()))
# 循环发送信号
break2 = False #break标志量
for i in range(1, 101):
if stop_status == 1: #停止信号1
self.valueChanged.emit(0)
#这个地方如果有进程锁,需要在这里解锁,当然也可以直接用break,但是break会执行后面的语句
print('程序结束')
return
elif stop_status == 2: #暂停信号2
while 1:
if stop_status == 2:
time.sleep(0.1) #必须有time.sleep 可以有效降低cpu消耗
continue
elif stop_status == 1: #停止信号1
break2 = True #break标志量,外层继续执行break
break #跳出无限循环
else: #恢复信号0
break
else:
pass
if(break2): #跳出外层for循环
break
print('value', i)
self.valueChanged.emit(i)
time.sleep(0.5)
self.status.emit(0)
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
# 垂直布局
layout = QVBoxLayout(self)
self.progressBar = QProgressBar(self)
self.progressBar.setRange(0, 100)
layout.addWidget(self.progressBar)
self.startButton = QPushButton('开启线程', self, clicked=self.onStart)
layout.addWidget(self.startButton)
self.suspendButton = QPushButton('挂起线程', self, clicked=self.onSuspendThread, enabled=False)
layout.addWidget(self.suspendButton)
self.resumeButton = QPushButton('恢复线程', self, clicked=self.onResumeThread, enabled=False)
layout.addWidget(self.resumeButton)
self.stopButton = QPushButton('终止线程', self, clicked=self.onStopThread, enabled=False)
layout.addWidget(self.stopButton)
# 当前线程id
print('main id', int(QThread.currentThreadId()))
# 子线程
self._thread = Worker(self)
#self._thread.finished.connect(self._thread.deleteLater)
self._thread.valueChanged.connect(self.progressBar.setValue)
def onStart(self):
global stop_status
stop_status = 0
print('main id', int(QThread.currentThreadId()))
self._thread.start() # 启动线程
self.startButton.setEnabled(False)
self.suspendButton.setEnabled(True)
self.stopButton.setEnabled(True)
def onSuspendThread(self):
global stop_status
stop_status = 2
print('挂起线程')
self.suspendButton.setEnabled(False)
self.resumeButton.setEnabled(True)
def onResumeThread(self):
global stop_status
stop_status = 0
print('恢复线程')
self.suspendButton.setEnabled(True)
self.resumeButton.setEnabled(False)
def onStopThread(self):
global stop_status
stop_status = 1
self.startButton.setEnabled(True)
self.resumeButton.setEnabled(False)
self.progressBar.setRange(0, 100)
print('终止线程')
self.stopButton.setEnabled(False)
if __name__ == '__main__':
import sys
import os
print('pid', os.getpid())
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
检查文件目录是否存在的最优雅方法是什么?如果不存在,则使用Python创建目录? 这是我尝试过的: 不知何故,我错过了os.path.exists (感谢kanja,Blair和Douglas)。 这就是我现在所拥有的: 是否有“打开”标志,使它自动发生? #1楼 Python 3.5以上版本: pathlib.Path.mkdir使用的pathlib.Path.mkdir...
问题: 昨天在开发调试过程中发现程序在运行一段时间后会crash,报错信息:RuntimeError: Set changed size during iteration,下面是部分源代码: 求助google后,得到一遍文章 :Recursion: how to avoid Python set changed set during iteration RuntimeError 恍然大悟,我怎么能...
我猜各位 JSer,或多或少都遇到过这种错误: Uncaught TypeError: Cannot read property 'someProp' of undefined。当我们从 null 或者 undefined 上去读某个属性时,就会报这种错误。尤其一个复杂的前端项目可能会对接各种各样的后端服务,某些服务不可靠,返回的数据并不是约定的格式时,就很容易出现这种错误。 这里有一个深度嵌套的...
原文地址:How can I use CSS-in-JS securely? 原文作者:James K Nelson 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:Yuuoniy 校对者:HydeSong Tina92 CSS-in-JS 允许我把 JavaScript 变量插入到 CSS 中,这给了我很大的权限,但这样安全吗? 恶意用户...
用迭代器删除是没问题的...
前言 · 零 我们知道,在python里面要终止一个线程,常规的做法就是设置/检查 --->标志或者锁方式来实现的。 这种方式好不好呢? 应该是不大好的!因为在所有的程序语言里面,突然地终止一个线程,这无论如何都不是一个好的设计模式。 同时 有些情况下更甚,比如: 线程打开一个必须合理关闭的临界资源时,比如打开一个可读可写的文件; 线程已经创建了好几个其他的线程,这些线程也是需...
卸载python 卸载python3.6及其所有依赖。如需卸载其它系统程序,也可使用如下命令,如卸载dnf或者yum,卸载完成后重新键入dnf或者yum即可。(本人就是卸载python失误后,dnf和yum全部失效的受害者T_T,折腾了好半天才修复,千万不要乱删系统环境的python,由于高版本的dnf和yum依赖于python环境,所以删除python一定要用下面的方法,不然会很麻烦。) 安装p...
步骤 1、在一些特殊环境下,slave节点可能会尝试从错误的位置(position)进行启动。为了减少这种风险,要先停止io thread,从而不接收新的事件信息 mysql> stop slave io_thread; mysql> show slave status\G mysql> stop slave sql_thread; //等sql thread应用完所有的even...
C#线程操作的各个方法 在UI事件后需要执行大量耗费时间的代码时,通常需要将此代码放入线程中去执行,本文着重讲一下从线程的创建到执行及终止的一系列操作。 一、线程的创建。 线程创建分为带参数线程与不带参数线程,带参数时需要用object做封装,多个参数使用object[] data,以下为代码 二、线程的异步执行 在线...
本博客所有文章分类的总目录:【总目录】本博客博文总目录-实时更新 开源Math.NET基础数学类库使用总目录:【目录】开源Math.NET基础数学类库使用总目录 前言 数论就是指研究整数性质的一门理论。数论=算术。不过通常算术指数的计算,数论指数的理论。整数的基本元素是素数...