努力是为了让你的目标更明确,但方向若错了,那可能就成了最遗憾的意外了
今天学习一下Python里的多线程的应用。但大家要清楚什么是线程,什么是进程,要区分二者概念
线程是一个轻量级的子进程,是最小的处理单元。可以说线程是进程的子集。
线程是独立的,一个线程发生错误,不影响其他线程正常执行。
进程是指正在运行中的应用程序。每个进程都有自己独立的内存空间,当用户启动一个进程时,操作系统就会为该进程分配一个独立的内存空间,让应用程序在独立内存中运行
我们知道python是解释型语言,程序是从上向下解释一句执行一句,如果上面的程序出现的死循环,则下方的程序时不会执行的。接下来就做一个简单的测试。
import time # 导入时间模块
def test1():
while True:
print("线程1")
time.sleep(1) # 延时1秒防止数据太快
def test2():
while True:
print("线程2")
time.sleep(1) # 延时1秒防止数据太快
if __name__ == '__main__':
test1()
test2()
我们可以看到程序执行到test(1)时进入了死循环,所以test(2)不执行。那么如何处理这类问题呢?这里我们就要用到多进程处理。
多进程处理
这里用到了一个模块threading
首先导入这个模块
import threading # 导入线程模块
import time # 导入时间模块
# 定义一个线程1函数
def test1():
while True:
print("线程1")
time.sleep(1) # 延时1秒防止数据太快
# 定义一个线程2函数
def test2():
while True:
print("线程2")
time.sleep(1) # 延时1秒防止数据太快
if __name__ == '__main__':
t1 = threading.Thread(target=test1) # 设置为线程
t1.start() # 开启线程1
t2 = threading.Thread(target=test2) # 设置为线程
t2.start() # 开启线程2
执行效果
从上面的图片我们可以看出当线程处理时,并不是线程1执行一句,线程2执行一句,而是二者随机执行,所以在相同时间内,线程1和线程2执行的次数不一样多。这个就需要我们特别注意,用多线程处理全局变量时可能会出错。
我们可以看到当线程1出错时,并不影响线程2的执行,所以线程互相不影响。
就拿最简单的例子来说,在一个窗口实时显示刷新当前的时间
接下来就是代码的处理
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5 import QtCore, QtGui, QtWidgets
import time
class backendthread(QThread): # 声明一个类
updata = pyqtSignal(str) # 一个字符串的类的信号
def run(self):
while True:
data = time.ctime() # 获取本地时间
self.updata.emit(str(data))
time.sleep(1) # 睡眠一秒
注意导入相关线程和信号类库。如果是用QTdesigner生成的py代码,就要在生成的代码里去写
写完信号后我们要写一个槽去用这个信号
def initUI(self):
self.back= backendthread()
self.back.updata.connect(self.display) # 链接到一个display槽函数
self.back.start()
def display(self,data): # 编写这个槽函数
self.text2.setText(data) # 将时间显示出来
下面定义的def initUI(self):函数,注意在前面的def setupUi(self, Form):下面添加
最后我附上我的这个用designer生成并修改后的登录界面的py文件的所有程序,由于里面的控件多所以程序也多,大家只用看第一个函数和后面两个函数就可以了。
我没有给出我的main.py,但上几篇博客里已经给出来。由于今天没修改main.py,所以没必要给,不然代码会更多。
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5 import QtCore, QtGui, QtWidgets
import time
class backendthread(QThread):
updata = pyqtSignal(str)
def run(self):
while True:
data = time.ctime()
self.updata.emit(str(data))
time.sleep(1)
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(861, 479)
Form.setBaseSize(QtCore.QSize(0, 0))
Form.setStyleSheet("\n"
"QWidget {\n"
"border-image:url(C:/Users/DELL/Pictures/Saved Pictures/1.jpg);\n"
"}\n"
"\n"
"QTextBrowser {\n"
"border-image:url();\n"
"}\n"
"QLineEdit {\n"
"border-image:url();\n"
"}\n"
"QComboBox {\n"
"border-image:url();\n"
"}\n"
"QLabel {\n"
"border-image:url();\n"
"}\n"
"QPushButton {\n"
"border-image:url();\n"
"}")
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.textBrowser = QtWidgets.QTextBrowser(Form)
self.textBrowser.setMaximumSize(QtCore.QSize(165000, 115))
self.textBrowser.setStyleSheet("QTextBrowser\n"
"{\n"
"background-color: rgba(255,255,255,0);\n"
"border:none;\n"
"\n"
"}")
self.textBrowser.setObjectName("textBrowser")
self.verticalLayout.addWidget(self.textBrowser)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.text1 = QtWidgets.QTextBrowser(Form)
self.text1.setMaximumSize(QtCore.QSize(200, 30))
font = QtGui.QFont()
font.setFamily("AcadEref")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.text1.setFont(font)
self.text1.setStyleSheet("QTextBrowser\n"
"{\n"
"background-color: rgba(255,255,255,180);\n"
"border:none;\n"
"color:#55007f;\n"
"}")
self.text1.setObjectName("text1")
self.gridLayout.addWidget(self.text1, 1, 5, 1, 1)
self.label_4 = QtWidgets.QLabel(Form)
self.label_4.setMaximumSize(QtCore.QSize(140, 16777215))
font = QtGui.QFont()
font.setFamily("AcadEref")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_4.setFont(font)
self.label_4.setStyleSheet("QLabel\n"
"{\n"
"color:#ffff00;\n"
"\n"
"}")
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 1, 3, 1, 1)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem1, 8, 2, 1, 1)
self.comboBox = QtWidgets.QComboBox(Form)
self.comboBox.setMaximumSize(QtCore.QSize(16777215, 16770000))
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.gridLayout.addWidget(self.comboBox, 1, 2, 1, 1)
self.lineEdit_3 = QtWidgets.QLineEdit(Form)
self.lineEdit_3.setMinimumSize(QtCore.QSize(0, 25))
self.lineEdit_3.setMaximumSize(QtCore.QSize(200, 40))
self.lineEdit_3.setStyleSheet("QLineEdit\n"
"{\n"
"background-color: rgba(255,255,255,180);\n"
"border:none;\n"
"}")
self.lineEdit_3.setObjectName("lineEdit_3")
self.gridLayout.addWidget(self.lineEdit_3, 9, 5, 1, 1)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem2, 8, 1, 1, 1)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem3, 1, 6, 1, 1)
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem4, 2, 3, 1, 1)
spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem5, 10, 3, 1, 1)
self.label_3 = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setFamily("Adobe 宋体 Std L")
font.setPointSize(11)
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.label_3.setFont(font)
self.label_3.setStyleSheet("QLabel\n"
"{color:#ffff00;\n"
"}")
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setFamily("新宋体")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_2.setFont(font)
self.label_2.setStyleSheet("QLabel\n"
"{\n"
"color:#ffff00;\n"
"\n"
"}")
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 9, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setFamily("AcadEref")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_5.setFont(font)
self.label_5.setStyleSheet("QLabel\n"
"{\n"
"color:#ffff00;\n"
"\n"
"}")
self.label_5.setObjectName("label_5")
self.gridLayout.addWidget(self.label_5, 7, 3, 1, 1)
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setMaximumSize(QtCore.QSize(117, 25))
self.lineEdit.setStyleSheet("QLineEdit\n"
"{\n"
"background-color: rgba(255,255,255,180);\n"
"border:none;\n"
"}")
self.lineEdit.setObjectName("lineEdit")
self.gridLayout.addWidget(self.lineEdit, 7, 2, 1, 1)
self.label = QtWidgets.QLabel(Form)
self.label.setMaximumSize(QtCore.QSize(150, 16777215))
font = QtGui.QFont()
font.setFamily("AcadEref")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label.setFont(font)
self.label.setStyleSheet("QLabel\n"
"{\n"
"color:#ffff00;\n"
"\n"
"}")
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 7, 1, 1, 1)
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setEnabled(False)
self.pushButton_2.setStyleSheet("QPushButton\n"
"{\n"
"background-color:blue;\n"
"color:#ffffff;\n"
"font: 75 13pt \"新宋体\";\n"
"}")
self.pushButton_2.setObjectName("pushButton_2")
self.gridLayout.addWidget(self.pushButton_2, 11, 2, 1, 1)
self.text2 = QtWidgets.QTextBrowser(Form)
self.text2.setMaximumSize(QtCore.QSize(200, 30))
font = QtGui.QFont()
font.setFamily("新宋体")
font.setPointSize(8)
font.setBold(False)
font.setWeight(50)
self.text2.setFont(font)
self.text2.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.IBeamCursor))
self.text2.setAutoFillBackground(True)
self.text2.setStyleSheet("QTextBrowser\n"
"{\n"
"background-color: rgba(255,255,255,0);\n"
"border:none;\n"
"color:#00ff00;\n"
"}")
self.text2.setLineWidth(2)
self.text2.setReadOnly(True)
self.text2.setOverwriteMode(False)
self.text2.setSearchPaths([])
self.text2.setOpenLinks(True)
self.text2.setObjectName("text2")
self.gridLayout.addWidget(self.text2, 7, 5, 1, 1)
self.lineEdit_4 = QtWidgets.QLineEdit(Form)
self.lineEdit_4.setMinimumSize(QtCore.QSize(0, 25))
self.lineEdit_4.setMaximumSize(QtCore.QSize(200, 16777215))
self.lineEdit_4.setAutoFillBackground(False)
self.lineEdit_4.setStyleSheet("QLineEdit\n"
"{\n"
"background-color: rgba(255,255,255,180);\n"
"border:none;\n"
"}")
self.lineEdit_4.setObjectName("lineEdit_4")
self.gridLayout.addWidget(self.lineEdit_4, 11, 5, 1, 1)
self.label_6 = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setFamily("AcadEref")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_6.setFont(font)
self.label_6.setStyleSheet("QLabel\n"
"{\n"
"color:#ffff00;\n"
"\n"
"}")
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 11, 3, 1, 1)
self.label_7 = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setFamily("AcadEref")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.label_7.setFont(font)
self.label_7.setStyleSheet("QLabel\n"
"{\n"
"color:#ffff00;\n"
"\n"
"}")
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 9, 3, 1, 1)
self.lineEdit_2 = QtWidgets.QLineEdit(Form)
self.lineEdit_2.setMaximumSize(QtCore.QSize(117, 25))
self.lineEdit_2.setAutoFillBackground(False)
self.lineEdit_2.setStyleSheet("QLineEdit\n"
"{\n"
"background-color: rgba(255,255,255,180);\n"
"border:none;\n"
"}")
self.lineEdit_2.setText("")
self.lineEdit_2.setObjectName("lineEdit_2")
self.gridLayout.addWidget(self.lineEdit_2, 9, 2, 1, 1)
spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem6, 2, 1, 1, 1)
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setEnabled(True)
self.pushButton.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.pushButton.setStyleSheet("QPushButton\n"
"{\n"
"background-color:blue;\n"
"color:#ffffff;\n"
"font: 75 13pt \"新宋体\";\n"
"}")
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 11, 1, 1, 1)
spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem7, 11, 0, 1, 1)
self.text3 = QtWidgets.QTextBrowser(Form)
self.text3.setMaximumSize(QtCore.QSize(200, 30))
self.text3.setStyleSheet("QTextBrowser\n"
"{\n"
"background-color: rgba(255,255,255,0);\n"
"border:none;\n"
"color:#ffff00;\n"
"\n"
"}\n"
"")
self.text3.setObjectName("text3")
self.gridLayout.addWidget(self.text3, 8, 5, 1, 1)
self.verticalLayout.addLayout(self.gridLayout)
spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem8)
self.horizontalLayout.addLayout(self.verticalLayout)
self.initUI()
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "系统登录"))
self.textBrowser.setHtml(_translate("Form", "\n"
"\n"
"基于活体检测的PCA多特征人脸识别门禁考勤管理系统
"))
self.text1.setHtml(_translate("Form", "\n"
"\n"
"
"))
self.label_4.setText(_translate("Form", " 登录状态显示:"))
self.comboBox.setItemText(0, _translate("Form", "管理员"))
self.comboBox.setItemText(1, _translate("Form", "普通用户"))
self.label_3.setText(_translate("Form", " 权限选择:"))
self.label_2.setText(_translate("Form", " 密 码:"))
self.label_5.setText(_translate("Form", " 时间:"))
self.label.setText(_translate("Form", " 用户名:"))
self.pushButton_2.setText(_translate("Form", "注册"))
self.text2.setHtml(_translate("Form", "\n"
"\n"
"
"))
self.label_6.setText(_translate("Form", " 超级权限:"))
self.label_7.setText(_translate("Form", " 验证码:"))
self.pushButton.setText(_translate("Form", "登陆"))
self.text3.setHtml(_translate("Form", "\n"
"\n"
"4+8=
"))
def initUI(self):
self.back= backendthread()
self.back.updata.connect(self.display)
self.back.start()
def display(self,data):
self.text2.setText(data)
到这就全部编写完成,我们来运行一下看看效果,时间确实是显示出来了。但原谅我没gif图。
其实PyQt5里的用多线程刷新UI界面还是不太好写的,我也是早上查了好多资料才实现的,像类似这种问题b站也有一些教程。我这篇可能偏实际开发,因为我就是在我现在正在做的项目上直接去做的,代码有点多,不适合新手去看,因为新手可能看不懂,不知道这么多代码什么地方该看什么地方是重点,什么地方可以直接跳过不看。
建议
总之一句话,想学好多线程,就要多看,多查,多尝试。这篇博文只是针对开发时解决的一个时间实时显示的功能。一个案例并不能学懂线程,一定要多看一些实战案例。这样才能有更深一步的了解。
注:我也并不是专业开发python的,只是一个python的爱好者。