开发者社区> 问答> 正文

一半的线程没有完成和消失

因此,我目前有一个PYQT应用程序,它结合了python内置的线程和QT Qthread/worker系统来支持异步活动 生成线程/工作者的代码是process_batch,它包含在一个名为Scraper的类中,该类是一个QObject

def process_batch(self, batch):
    for worker in batch:
        self.host.threads.append(QThread())
        th = self.host.threads[len(self.host.threads)-1]
        worker.moveToThread(th)
        th.started.connect(worker.process)
        qApp.aboutToQuit.connect(th.quit)
        worker.finished.connect(worker.deleteLater)
        th.finished.connect(th.deleteLater)
    for thread in self.host.threads:
        thread.start()
        self.activeThreads += 1

self.host。线程是一个列表变量helf由ScraperHost对象,该批处理变量是一个标准的python列表,有50个类:

class ScraperWorker(QObject):
    complete = pyqtSignal(str)
    start = pyqtSignal(str)
    finished = pyqtSignal()

    def __init__(self, url, task, _id):
        QObject.__init__(self)
        self.url = url
        self.task = task
        self.id = _id
        self.start.connect(self.process)

    def __str__(self):
        return self.url

    @pyqtSlot()
    def process(self):
        time.sleep(float(random.random() * random.randint(1,3)))      
        #self.complete.emit(str(self.id))
        self.finished.emit()

时间。添加sleep是为了查看随机间隔线程的补全是否会修复这个问题,但它没有 最初,我遇到了一个问题:process_batch函数完成时,线程在完成之前被删除,所以我实现了self.host。防止它们被垃圾回收的线程。 线程包含如下:

class ScraperHost(threading.Thread):
    def __init__(self, threadID, urls, task):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.scraper = Scraper(urls, task, self)
        self.threads = []

    def run(self):
        self.scraper.run()

刮板主机是创建在我的主窗口:

def selectFileList(self):
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, "Select List","", "Excel File (*.xls *.xlsx)", options=options)
        if fileName:
            ...
            ...
            self.ScraperHost = ScraperHost(0, urls, "index")
            self.ScraperHost.run()

目前,我可以运行零错误的函数/程序,但它只完成了线程的一半。它不会给我任何错误,信息,或任何指示,为什么他们没有完成。如果我将批处理大小增加到100,它就完成了50。如果我在VS代码中以调试模式运行它,我可以看到所有50个线程都被正确创建,并且都在主机中。线程变量。如果我在调试模式下一步一步地完成线程的创建,它们都将正确地完成,但是如果我只是正常地运行程序,只有一半将完成。每次结束的25个线程都是不同的,因为它们等待的时间是随机的。worker的self.finished.emit()只打印线程的ID,这是我看到多少完成的方式 旁注:通过更多,有时所有,但没有一致性的线程,当运行从空闲相对于VS代码

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


import threading
import time
import random

scraperhost = None

class ScraperHost(threading.Thread):
    def __init__(self, threadID, urls, task):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.scraper = Scraper(urls, task, self)
        self.threads = []

    def run(self):
        self.scraper.run()

class Scraper(QObject):
    output = pyqtSignal(str)
    complete = pyqtSignal()

    def __init__(self, urls, task, host):
        QObject.__init__(self)
        self.urls = urls
        self.batches = []
        self.activeThreads = 0
        self.task = task
        self.host = host

    def __del__(self):
        self.wait()

    def run(self):
        batch_size = 50 
        batch_count = 1
        for batch in range(0, batch_count):
            self.batches.append([])
            for i in range (0, batch_size):
                try:
                    c_url = "www.website.com"
                    worker = ScraperWorker(c_url, self.task, i)
                    worker.complete.connect(self.worker_finished)
                    self.batches[batch].append(worker)
                except IndexError:
                    break
        if len(self.batches) == 0:
            return
        self.process_batch(self.batches.pop())

    @pyqtSlot(str)
    def worker_finished(self, ss):
        self.activeThreads -= 1  
        print(self.activeThreads)



    def process_batch(self, batch):
        for worker in batch:
            self.host.threads.append(QThread())
            th = self.host.threads[len(self.host.threads)-1]
            worker.moveToThread(th)
            th.started.connect(worker.process)
            qApp.aboutToQuit.connect(th.quit)
            worker.finished.connect(worker.deleteLater)
            th.finished.connect(th.deleteLater)
        for thread in self.host.threads:
            thread.start()
            self.activeThreads += 1


class ScraperWorker(QObject):
    complete = pyqtSignal(str)
    start = pyqtSignal(str)
    finished = pyqtSignal()

    def __init__(self, url, task, _id):
        QObject.__init__(self)
        self.url = url
        self.task = task
        self.id = _id
        self.start.connect(self.process)

    def __str__(self):
        return self.url

    @pyqtSlot()
    def process(self):
        time.sleep(float(random.random() * random.randint(1,3)))      
        self.complete.emit(str(self.id))
        self.finished.emit()









def main():

    app = QApplication([])
    ex = QWidget()
    ex.show()
    global scraperhost
    scraperhost = ScraperHost(0, [], "index")
    scraperhost.start()
    app.exec_()
    return

main()

问题来源StackOverflow 地址:/questions/59383422/half-of-threads-randomly-not-completing-and-vanishing

展开
收起
kun坤 2019-12-27 10:28:23 619 0
1 条回答
写回答
取消 提交回答
  • 在旧的单处理器系统中,各个线程只是占用处理器的一段时间片,因此不会出现一个线程运行到一半的时候,另一个线程又开始。但是,现在的机器一般都是多处理器系统,实现了真正的并行运行,因此这种情况肯定是会发生的。

    2019-12-27 16:31:17
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载

相关实验场景

更多