Pyqt5 多线程 QThread 要如何创建多个线程呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
itIsUnbelievable
V2EX    Python

Pyqt5 多线程 QThread 要如何创建多个线程呢?

  •  
  •   itIsUnbelievable 2019-08-22 11:33:42 +08:00 5965 次点击
    这是一个创建于 2241 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我写了一个类继承 QObject,然后用 movetothread 将前面那个实例放入一个继承 Qthread 的线程类,通过信号槽来连接。但是由于我接触 pyqt 没多久,对多线程这块不太熟,目前我只知道创建一个子线程将 ui 和业务逻辑分开,不知道怎么创建多个线程同时处理。我的业务场景是点击一个按钮同时对 16 个文件夹中的视频文件进行人脸分析,用 opencv 和百度云人脸识别 api。现在卡在如何创建多个线程这里了,第一次发帖,希望 v 站的老哥给点建议。非常感谢。

    14 条回复    2019-08-24 10:32:43 +08:00
    chengxiao
        1
    chengxiao  
       2019-08-22 11:46:07 +08:00
    Qthread 里只放线程里的运行代码,要多个线程就直接循环创建多个 Qthread 类实例就好了啊
    itIsUnbelievable
        2
    itIsUnbelievable  
    OP
       2019-08-22 12:05:29 +08:00
    @chengxiao
    ```
    class BaiduYunObject(QObject):
    stop_procession_signal=pyqtSignal()

    def __init__(self,parent=None):
    super(BaiduYunObject,self).__init__(parent)

    def main(self):
    print(11)
    self.stop_procession_signal.emit()



    class BaiduYunProcessingThread(QObject):
    def __init__(self,detect_url,search_url,add_url,multi_search_url):
    super().__init__()
    self.process_thread= QThread()
    self.process_thread1= QThread()
    self.procession=BaiduYunObject()
    self.procession.moveToThread(self.process_thread1)
    self.procession.moveToThread(self.process_thread)
    self.process_thread.started.connect(self.procession.main)
    self.process_thread1.started.connect(self.procession.main)
    self.procession.stop_procession_signal.connect(self.stop_process) #线程结束信号槽
    self.process_thread.start()
    self.process_thread1.start()

    def stop_process(self):
    self.process_thread.quit()

    ```
    我创建了两个线程实例测试了下,是能打印出两个 11.但是 11 前面报了下面这个错误:
    QObject::moveToThread: Current thread (0x1d0369badf0) is not the object's thread (0x1d068d35530).
    Cannot move to target thread (0x1d068d35f50)

    所以我有点疑问,不知道这样创建合不合理。而且还有个问题是如何使用循环创建多个线程实例,比如创建 16 个线程应该如何用 for 循环动态创建变量,毕竟 format()只能用于字符串,如果想要循环创建形如 process_thread_1,process_thread_2 这样的变量该怎么创建呢,我试过 locals(),但没成功,希望能给建议。
    itIsUnbelievable
        3
    itIsUnbelievable  
    OP
       2019-08-22 12:53:26 +08:00
    @chengxiao 而且我把 main()函数改成
    for i in range(10):
    print(i)
    发现两个线程不是并发的,而是一个线程运行结束后再运行另一个。
    输出为 01234567890123456789
    chengxiao
        4
    chengxiao  
       2019-08-22 13:08:37 +08:00
    额....
    @itIsUnbelievable 因为你的程序没有写进 Qhtread 里啊 缩进太乱没看懂
    不过我感觉你的 BaiduYunObject 应该继承 Qthread 而不是 Qobject
    然后生成的 BaiduYunObject 的实例就是线程运行
    BaiduYunProcessingThread 这个也写的有问题 建议还是看看 pyqt 的线程案例照着写一个吧
    allenforrest
        5
    allenforrest  
       2019-08-22 13:13:07 +08:00   1
    可以改用 QThreadPool 和 QRunnable,管理线程更简单。
    每个要处理的任务,都定义成 QRunnable 对象的子类,实现 Run 方法。
    然后主线程创建 threadPool,每次要创建一个线程干活的时候,就 start 一个 QRunnable 对象即可,把对象的 autoDelete 设置为 true,run 跑完就自动销毁回收线程了。
    itIsUnbelievable
        6
    itIsUnbelievable  
    OP
       2019-08-22 13:25:26 +08:00
    @chengxiao 继承 Qthread 然后运行 run()方法的那种写法我之前试过,不过 google 了好久发现说 QT 的作者不支持这种写法,所以改成继承了 QObject 这种写法。https://blog.csdn.net/qq_39607437/article/details/79213717 他是这么说的:
    ```
    QtCore.QThread 是一个管理线程的类,当我们使用其构造函数的时候,便新建了一个线程。这里要强调,QThread 是一个线程管理器,不要把业务逻辑放在这个类里面,Qt 的作者已经多次批评继承 QThread 类来实现业务逻辑的做法。
    ```
    我就是按照这篇修改了写法。但是他也没讲这种写法创建很多个线程要怎么弄,所以我就试着创建多个线程实例,并将负责复杂计算业务逻辑的那个类实例放入线程类当中,现在的结果就如上面所说,线程好像不是同时运行的。 我现在很懵逼
    itIsUnbelievable
        7
    itIsUnbelievable  
    OP
       2019-08-22 13:33:09 +08:00
    重新发下这部分代码:在 UI 主线程实现点击按钮后创建一个 BaiduYunProcessingThread 类实例。
    class BaiduYunObject(QObject):
    stop_procession_signal=pyqtSignal()

    def __init__(self,parent=None):
    super(BaiduYunObject,self).__init__(parent)

    def main(self):
    for i in range(10):
    print(i)
    self.stop_procession_signal.emit()

    class BaiduYunProcessingThread(QObject):
    def __init__(self):
    super().__init__()
    self.process_thread= QThread()
    self.process_thread_1= QThread()
    self.procession=BaiduYunObject()
    self.procession.moveToThread(self.process_thread_1)
    self.procession.moveToThread(self.process_thread)
    self.process_thread.started.connect(self.procession.main)
    self.process_thread_1.started.connect(self.procession.main)
    self.procession.stop_procession_signal.connect(self.stop_process) #线程结束信号槽
    self.process_thread.start()
    self.process_thread_1.start()

    def stop_process(self):
    self.process_thread.quit()
    itIsUnbelievable
        8
    itIsUnbelievable  
    OP
       2019-08-22 13:37:19 +08:00
    @allenforrest 好的,非常感谢,我先去了解一下,感觉好像很有用。
    allenforrest
        9
    allenforrest  
       2019-08-22 13:40:52 +08:00
    @itIsUnbelievable 对,这代码多干净:

    #include <QCoreApplication>
    #include <QThreadPool>
    #include <QThread>
    #include <QRunnable>
    #include <QDebug>
    class MyRun : public QRunnable {
    public:
    void run() {
    int i=3;
    while(i) {
    i--;
    QThread::msleep(500);
    }
    }
    };
    int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    QThreadPool m;
    MyRun *run=new MyRun;
    if(!run->autoDelete()) {
    run->setAutoDelete(true);
    }
    m.start(run);

    m.waitForDone();
    return 0;
    }
    itIsUnbelievable
        10
    itIsUnbelievable  
    OP
       2019-08-22 14:02:16 +08:00
    @allenforrest 我刚才看到这样一句话:
    ```
    需要注意的是,QRunnable 不是一个 QObject,因此也就没有内建的与其它组件交互的机制。为了与其它组件进行交互,你必须自己编写低级线程原语,例如使用 mutex 守护来获取结果等。
    ```
    我想问下 QRunnable 支不支持信号槽机制呢?还有就是它可不可以在子线程中继续创建子线程?这个时候线程的执行顺序该如何保证呢?是要用 python 的 queue 吗?
    allenforrest
        11
    allenforrest  
       2019-08-23 15:19:57 +08:00
    @itIsUnbelievable 可以同时继承 QRunnable 和 QObject 哈
    woshidag
        12
    woshidag  
       2019-08-23 16:01:10 +08:00   1
    itIsUnbelievable
        13
    itIsUnbelievable  
    OP
       2019-08-24 10:27:03 +08:00
    @allenforrest 谢谢,我昨天看了一篇 QT 的文章就是继承了 QObject,我也就照着做了。而且在子线程中又创建了一个 threadPool,想要创建子线程就再 new 一个新的 runnable 类,测试了一下是可以在子线程下再创建子线程的。就是不太清楚线程中的共享数据问题
    itIsUnbelievable     14
    itIsUnbelievable  
    OP
       2019-08-24 10:32:43 +08:00
    @woshidag 这篇讲的也太好了吧,amazing,谢谢老哥!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1029 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 18:37 PVG 02:37 LAX 11:37 JFK 14:37
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86