谈谈QThread 多线程处理
多线程python 已有 threading, pyqt 又有 QThread, 一开始都容易有疑问,二者有何不同?应该那一个比较对,我是觉得二者皆可用,网上曾看过有人说,应儘量用 python 本身的 threading, QThread 是塬本针对 C++而写。
任务量较少的情况,我会直接用 threading, 任务量大且需向其它gui 物件传递讯息的情况,我会用QThread
这篇是写PyQt,所以这边我也只写 QThread部份
会想使用QThread,我所遇到的情况,是向网页,抓取资料,又遇网路过慢,延迟过久造成Gui介面等待过久,介面会卡卡、顿顿的。
首先先写介面,然后点击 startBtn 可以测试 无线程情况下,图形介面是不是卡卡的

# -*- coding: UTF8 -*-
import sys
import urllib2
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Window(QWidget):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
layout = QVBoxLayout()
hbox = QHBoxLayout()
self.edit = QTextEdit()
self.startBtn = QPushButton("Start")
self.stopBtn = QPushButton("Stop")
hbox.addStretch()
hbox.addWidget(self.startBtn)
hbox.addWidget(self.stopBtn)
layout.addWidget(self.edit)
layout.addLayout(hbox)
self.setLayout(layout)
# SIGNAL&SLOT
self.startBtn.clicked.connect(self.test)
def test(self):
url = 'http://blog.sina.com.cn/'
html = urllib2.urlopen(url).read()
length = len(html)
self.edit.append("Url:%s Content:%s" % (url, length))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
加入线程
class Worker(QThread):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.url = 'http://blog.sina.com.cn/'
def run(self):
html = br.urlopen(self.url).read()
length = len(html)
self.emit(SIGNAL("length"), self.url, str(length))
print 'success'
self.emit(SIGNAL("length"), self.url, str(length))
当线程完成任务时,我们请线程发送讯号"length",并传递url及所抓取网页的资料大小
主程式添加
class Window(QWidget):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
.
.
.
self.work = Worker()
# SIGNAL&SLOT
self.startBtn.clicked.connect(self.start)
self.connect(self.work, SIGNAL("length"),
self.updateUI)
def start(self):
self.work.start()
def updateUI(self, url, length):
self.edit.append("Url:%s Content:%s" % (url, length))
self.connect(self.work, SIGNAL("length"),
self.updateUI)
主程式这边接收刚线程传递出来的资料"length"
现在我们多添加一点任务给线程
import lxml.html as H
线程改写成
class Worker(QThread):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.url = 'http://blog.sina.com.cn/'
def run(self):
self.url = 'http://blog.sina.com.cn/'
html = urllib2.urlopen(self.url).read()
doc = H.document_fromstring(html)
urlList = doc.xpath('//a/@href')
for i in range(10):
url = urlList[i]
html = urllib2.urlopen(url).read()
length = len(html)
self.emit(SIGNAL("length"), url, str(length))
print 'success'
doc = H.document_fromstring(html)
urlList = doc.xpath('//a/@href')
这边我们用 lxml.html xpath语法 取得了,所有文章连结
让线程去跑十篇文章。
在跑文章时候,我们希望避免重复按下startBtn
应修改
def start(self):
self.work.start()
self.startBtn.setEnabled(False)
在任务一执行时,先关闭
self.startBtn
任务完成时,再开启 self.startBtn
主程式添加以下代码
self.connect(self.work, SIGNAL("finished()"),
self.finished)
def finished(self):
self.startBtn.setEnabled(True)

那如果我们希望执行当中,停止任务呢?
QMutex() 上锁吧!
最后整个程式代码如下:
# -*- coding: UTF8 -*-
import sys
import lxml.html as H
import urllib2
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Window(QWidget):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
layout = QVBoxLayout()
hbox = QHBoxLayout()
self.edit = QTextEdit()
self.startBtn = QPushButton("Start")
self.stopBtn = QPushButton("Stop")
hbox.addStretch()
hbox.addWidget(self.startBtn)
hbox.addWidget(self.stopBtn)
layout.addWidget(self.edit)
layout.addLayout(hbox)
self.setLayout(layout)
#
self.work = Worker()
# SIGNAL&SLOT
self.startBtn.clicked.connect(self.start)
self.stopBtn.clicked.connect(self.stop)
self.connect(self.work, SIGNAL("length"),
self.updateUI)
self.connect(self.work, SIGNAL("finished()"),
self.finished)
def start(self):
self.work.start()
self.startBtn.setEnabled(False)
def updateUI(self, url, length):
self.edit.append("Url:%s Content:%s" % (url, length))
def finished(self):
self.startBtn.setEnabled(True)
def stop(self):
self.work.stop()
self.startBtn.setEnabled(True)
class Worker(QThread):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.stoped = False
self.mutex = QMutex()
def run(self):
with QMutexLocker(self.mutex):
self.stoped = False
self.url = 'http://blog.sina.com.cn/'
html = urllib2.urlopen(self.url).read()
doc = H.document_fromstring(html)
urlList = doc.xpath('//a/@href')
for i in range(10):
url = urlList[i]
if self.stoped:
return
html = urllib2.urlopen(url).read()
length = len(html)
self.emit(SIGNAL("length"), url, str(length))
print 'success'
def stop(self):
with QMutexLocker(self.mutex):
self.stoped = True
def isStop(self):
with QMutexLocker(self.mutex):
return self.stoped
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
