Python和PySid中带超时的线程上载

2024-10-02 00:34:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一个基于线程。线程,多处理或队列以上载具有超时的项目列表。线程允许GUI保持响应。如果连接挂起,则应触发超时并正常退出程序。在

下面的示例可以工作,但是GUI仍然被阻塞。如何改进这一点以允许上传列表、手动取消进程、上传过程超时以及非阻塞GUI?在

from PySide.QtGui import * from PySide.QtCore import * import sys import time import threading class UploadWindow(QDialog): def __init__(self, parent=None): super(UploadWindow, self).__init__(parent) self.uploadBtn = QPushButton('Upload') mainLayout = QVBoxLayout() mainLayout.addWidget(self.uploadBtn) self.uploadBtn.clicked.connect(self.do_upload) self.progressDialog = QProgressDialog(self) self.progressDialog.canceled.connect(self.cancelDownload) self.progressDialog.hide() self.setLayout(mainLayout) self.show() self.raise_() def do_upload(self): self.uploadBtn.setEnabled(False) self.progressDialog.setMaximum(10) self.progressDialog.show() self.upload_thread = UploadThread(self) self.upload_thread.start() self.upload_thread_stopped = False #List of items to upload for i in range(10): self.upload_thread = UploadThread(i) self.upload_thread.start() self.upload_thread.join(5) self.progressDialog.setValue(i) if self.upload_thread_stopped: break self.progressDialog.hide() self.uploadBtn.setEnabled(True) def cancelDownload(self): self.upload_thread_stopped = True class UploadThread(threading.Thread): def __init__(self, i): super(UploadThread, self).__init__() self.i = i self.setDaemon(True) def run(self): time.sleep(0.25) #simulate upload time print self.i if __name__ == '__main__': app = QApplication(sys.argv) w = UploadWindow() sys.exit(app.exec_())


Tags: importselftimeinitdefsysgui线程
3条回答

最后,我通过采用概述的here方法解决了这个问题,我发现这是一个优雅的解决方案。我创建的类如下所示:

class UploadThread(threading.Thread):

    #input_q and result_q are Queue.Queue objects
    def __init__(self, input_q, result_q):
        super(UploadThread, self).__init__()
        self.input_q = input_q
        self.result_q = result_q
        self.stoprequest = threading.Event() #threadsafe flag

    def run(self):
        '''Runs indefinitely until self.join() is called. 
        As soon as items are placed in the input_q, then the thread will process them until the input_q is emptied.
        '''
        while not self.stoprequest.isSet(): #stoprequest can be set from the main gui
            try:
                # Queue.get with timeout to allow checking self.stoprequest
                num = self.input_q.get(True, 0.1) #when the queue is empty it waits 100ms before raising the Queue.Empty error
                print 'In thread, processing', num
                time.sleep(0.5)
                self.result_q.put(True) #Indicate to the main thread that an item was successfully processed.
            except Queue.Empty as e:
                continue

    def join(self, timeout=None):
        self.stoprequest.set()
        super(UploadThread, self).join(timeout)

在主线程中,创建上载线程,并在输入_q中加载要上载的项。创建了一个QTimer,通过检查结果中的内容来定期检查上传的进度。它还更新进度条。如果在超时时间内没有任何进展,则表明上载连接失败。在

使用的优点排队。排队对象用于线程之间的通信,即可以创建共享同一输入和结果队列的多个线程。在

GUI没有响应,因为您在do_upload中完成所有工作,从不返回主循环。在

另外,您可以调用Thread.join(),在线程完成之前阻塞所有内容(请参见https://docs.python.org/2/library/threading.html#threading.Thread.join

您应该使用PySide.QtCore.QThread来利用信号和插槽。 这是一个nice example in C++。我用PyQthere在Python3.4中实现了它,但是您也应该能够在PySide中使用它。在

您可能还需要查看PySide.QtCore.QProcess,以避免使用线程。在

在这里,我把一些代码组合在一起,可以实现我认为你想要的。在

对于实际的项目,请确保更好地跟踪上载的内容&;/或使用比.terminate()更安全的方法来按需停止线程。在

import sys
from PySide import QtGui, QtCore
import time

class MySigObj(QtCore.QObject):
    strSig = QtCore.Signal(str)
    tupSig = QtCore.Signal(tuple)

class UploadThread(QtCore.QThread):

    def __init__(self, parent=None):
        super(UploadThread, self).__init__(parent)
        self.endNow = False
        self.fileName = None
        self.sig = MySigObj()
        self.fileNames = []
        self.uploaded = []

    @QtCore.Slot(str)
    def setFileNames(self, t):
        self.fileNames = list(t)

    def run(self):
        while self.fileNames:
            print(self.fileNames)
            time.sleep(2)
            name = self.fileNames.pop(0)
            s = 'uploaded file: ' + name + '\n'
            print(s)
            self.sig.strSig.emit(s)
            self.uploaded.append(name)
            if len(self.fileNames) == 0:
                self.sig.strSig.emit("files transmitted: %s" % str(self.uploaded))
        else:
            time.sleep(1)   #if the thread started but no list, wait 1 sec every cycle thru
                            #that was this thread should release the Python GIL (Global Interpreter Lock)


class ULoadWin(QtGui.QWidget):

    def __init__(self, parent=None):
        super(ULoadWin, self).__init__(parent)
        self.upThread = UploadThread()
        self.sig = MySigObj()
        self.sig.tupSig.connect(self.upThread.setFileNames)
        self.upThread.sig.strSig.connect(self.txtMsgAppend)
        self.sig.tupSig.connect(self.upThread.setFileNames)
        self.layout = QtGui.QVBoxLayout()
        self.stButton = QtGui.QPushButton("Start")
        self.stButton.clicked.connect(self.uploadItems)
        self.stpButton = QtGui.QPushButton("Stop")
        self.stpButton.clicked.connect(self.killThread)
        self.testButton = QtGui.QPushButton("write txt\n not(?) blocked \nbelow")
        self.testButton.setMinimumHeight(28)
        self.testButton.clicked.connect(self.tstBlking)
        self.lbl = QtGui.QTextEdit()
        self.lbl.setMinimumHeight(325)
        self.lbl.setMinimumWidth(290)

        self.layout.addWidget(self.stButton)
        self.layout.addWidget(self.stpButton)
        self.layout.addWidget(self.testButton)
        self.layout.addWidget(self.lbl)

        self.setLayout(self.layout)

        self.l = ['a', 'list', 'of_files', 'we', 'will_pretend_to_upload', 'st', 'uploading']
        self.upThread.start()

    def tstBlking(self):
        self.lbl.append("txt not(?) blocked")

    def uploadItems(self):
        t = tuple(self.l)
        self.sig.tupSig.emit(t)
        self.upThread.start()

    def killThread(self):
        self.upThread.terminate()
        time.sleep(.01)
        self.upThread = UploadThread()

    @QtCore.Slot(str)
    def txtMsgAppend(self, txt):
        self.lbl.append(txt + "  |  ")


if __name__ == '__main__':
    app=QtGui.QApplication(sys.argv)
    widg=ULoadWin()
    widg.show()
    sys.exit(app.exec_())

相关问题 更多 >

    热门问题