栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

在PyQt QThreads中同步活动

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在PyQt QThreads中同步活动

仅仅因为您有两个循环在不同线程中进行相同数量的迭代,并不意味着它们将花费相同的时间长度。通常,每次迭代的内容都将花费一些时间来完成,并且由于您的循环在做不同的事情,因此它们(通常)将花费不同的时间长度。

此外,借助Python中的线程,全局解释器锁(GIL)阻止了线程在多核CPU上同时运行。GIL负责在线程之间切换并继续执行,然后再切换到另一个,然后再切换到另一个,依此类推。对于QThreads,这变得更加复杂,因为QThread中的Qt调用无需GIL即可运行(因此了解),但一般的python代码仍将与GIL一起运行。

因为GIL负责处理在任何给定时间正在运行的线程,所以我什至看到两个做相同的事情的线程以不同的速度运行。 因此,两个线程同时完成完全是巧合!

请注意,由于使用了GIL,两个cpu密集型任务在单独的线程中运行不会带来速度上的好处。为此,您需要使用多重处理。但是,如果您要输出受I /
O约束的任务(例如,通过主线程中的GUI进行用户界面操作,或者通过另一个线程中的网络通信,也就是通常花费大量时间等待程序外部内容的任务),触发某物),则线程化很有用。

因此,希望这有助于解释线程以及程序中发生的事情。

有两种方法可以更好地做到这一点。一种是将循环保留在您的线程中,而另一种则删除。然后使用qt signal /
slot机制调用一个函数,

MainWindow
该函数在其中运行曾经存在的循环的一次迭代。但是,这不能保证同步,只是您的QThread将首先完成(某些操作可能会减慢主线程的速度,从而使事件堆积,并且其中的功能要
MainWindow
等到以后再运行)。要完成同步,可以使用一个
threading.Event
对象使QThread等待
MainWindow
运行中的新函数。

示例(未经测试,很抱歉,但希望能给出这个主意!):

import threading#==========================================class TaskThread(QtCore.QThread):    setTime = QtCore.pyqtSignal(int,int)    iteration = QtCore.pyqtSignal(threading.Event, int)    def run(self):        self.setTime.emit(0,300)        for i in range(300): time.sleep(0.05) event = threading.Event() self.iteration.emit(event, i) event.wait()#==========================================class MainWindow(QtGui.QMainWindow):    _uiform = None    def __init__(self, parent=None):        QtGui.QMainWindow.__init__(self,parent)        self._uiform = Ui_MainWindow()        self._uiform.setupUi(self)        self._uiform.runButton.clicked.connect(self.startThread)    def startThread(self):        self._uiform.progressBar.setRange(0,0)        self.task = TaskThread()        self.task.setTime.connect(self.changePB)        self.task.iteration.connect(self.update_prog_bar)        self.task.start()    @QtCore.pyqtSlot(int,int)    def changePB(self, c, t):        self.proportionFinished = int(math.floor(100*(float(c)/t)))        self._uiform.progressBar.setValue(self.proportionFinished)        self._uiform.progressBar.setRange(0,300)        self._uiform.progressBar.setValue(0)    @QtCore.pyqtSlot(threading._Event,int)    def update_prog_bar(self,event, i)        self._uiform.progressBar.setValue(i+1)        print i        event.set()

请注意,使用

@QtCore.pyqtSlot()
装饰器是由于此处记录的问题。简而言之,当您使用时
signal.connect(my_function)
,您将忽略确定插槽行为的第二个参数(是否在
signal.emit()
调用时立即执行该插槽,或者是否在控件返回事件循环后立即执行该插槽(又称为队列),稍后再运行))。默认情况下,connect的这个可选参数会尝试自动确定通常可以进行哪种连接(请参阅此处)。但是,如果在知道连接是线程之间的连接之前进行了连接,并且使用
@pyqtSlot
,没有明确地将“
slot”定义为插槽,则pyQT会感到困惑!

有关装饰器的其他信息 :想到 装饰器
的最简单方法是将一个函数包装在另一个函数中的简写形式。装饰器将自己定义的函数替换为自己的函数,并且此新函数通常会在某个时候使用原始函数。因此,在这种

@pyqtSlot
情况下,信号发射实际上调用了由生成的pyqt函数
@pyqtSlot
,该函数最终调用了您编写的原始函数。
@pyqtSlot
装饰器接受与插槽参数类型匹配的参数的事实是pyqt装饰器的实现细节,通常不代表装饰器。仅说明您的插槽期望通过连接的信号传递指定类型的数据。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/652923.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号