PyQt 编程中多线程应该用 QThread、QTimer 还是 threading??

2018-01-31 13:20:01 +08:00
 XIVN1987

按我的理解,由于 GIL 的存在,threading.Thread 肯定无法利用多核,任意时刻只有一个线程在跑; QThread 的话在 C++里肯定是能多个同时跑的,但在 PyQt 里它执行的也是 Python 代码,所以应该也和 threading 一样并不能真的并行;而 QTimer 似乎原本就是在创建它的那个线程里跑的,但既然大家都没法真的并行,那跟另外两个似乎是一回事儿,,而且 QTimer 写起来感觉更简洁、直观,也不用 sleep(),,所以我觉得写 PyQt 程序的时候并发逻辑用 QTimer 写就行了,,

14252 次点击
所在节点    Python
32 条回复
XIVN1987
2018-01-31 17:39:21 +08:00
@justou

感谢回复,,

可你也要考虑 PyQt 和 Qt 的区别,Qt 里面是有真正的并行执行的,,两个线程分别占一个 CPU 核、并行执行;这时候 QThread 当然比 QTimer 好 100 倍

可是 PyQt 里面由于 GIL 的问题,你开了 QThread 它和主线程也只是交替执行的,,并没有真正的并行,,这时候感觉线程和 QTimer 区别就没那么明显了
justou
2018-01-31 18:23:24 +08:00
@XIVN1987 如果是要在 PyQt 程序中进行密集计算的话, 我会用一个 QThread 来管理一些进程, 或者干脆把密集计算部分用 C++来实现; 如果线程只是进行 IO 操作的话, PyQt 的 QThread 和 C++的 QThread 跑起来感觉不到任何差别, 甚至可以利用协程, 这比 C++的 QThread 有更好的并发.

用 QThread 不用 Timer 很大程度上是从设计上考虑, 用 QThread 可以形成更好的程序结构. 用 QThread 当线程 /进程管理者, 负责跟界面的交互, 而不是生成一堆 QThread 去完成具体的任务
wwqgtxx
2018-01-31 18:47:50 +08:00
@justou 其实吧,要是能在 c++中无缝操作 python 的 list 和 dict 就完美了,可惜 python 并没有提供官方的 c++接口
weyou
2018-01-31 19:12:10 +08:00
@crysislinux 恩,可能有点误解了
justou
2018-01-31 19:17:51 +08:00
@wwqgtxx 为什么有这种需求呢?
wwqgtxx
2018-01-31 21:16:55 +08:00
@justou 有些时候希望把一些运算量大的部分用 c++写,但是数据源依然是来自 python 代码,而这个时候,如果需要处理大量数据,那么这些数据就一定是放在 list 或者 dict 中的,有些时候还要求返回的依然是一个 list,所以如果可以在 c++中像 std::vector 以及 std::map 中操作 list 和 map 那么互操作性就大大增加了
这点 Boost.Python 做的就挺好,但是整个 boost 类库有点过于庞大了,要是能拆分出来就完美了
justou
2018-01-31 22:07:31 +08:00
@wwqgtxx "大量数据"要看具体类型, 数值数据用 list 存储是极其低效的, 可以用标准库的 array 或 numpy 存储, 想要避开 GIL 处理字符串可以在 Cython 中直接使用 C++的容器(string, vector, map 等, http://docs.cython.org/en/latest/src/userguide/wrapping_CPlusPlus.html ). array 和 numpy 也可以很容易把底层指针暴露给 C++处理

没实际用过 boost python, 感觉不如 Cython 简便直观, 有空深入学习下. 要拆分出来应该很容易, 只需要单独编译 boost python 库就行了 http://www.boost.org/doc/libs/1_66_0/libs/python/doc/html/building/installing_boost_python_on_your_.html
wizardforcel
2018-01-31 22:13:19 +08:00
qtimer 不是多线程,它是把消息定期插入消息队列,消息队列各个消息是串行的。
wizardforcel
2018-01-31 22:16:35 +08:00
@weyou 是限制在单核上的多线程。因为有调度,执行顺序还是随机的。
wwqgtxx
2018-02-01 08:09:02 +08:00
@justou 很多情况下存在数据来源不可控的问题,原来的代码是使用纯 python 代码写的,自然也就没有用 array 和 numpy 的容器,而有些运算是需要做一些修改源数组的,这时候如果再写一部分衔接代码在两种数据结构之间拷贝就不太划来了
wizardforcel
2018-02-01 13:08:11 +08:00
@XIVN1987 还是有区别的。比如 qtimer 里面长时间 io 操作会卡界面。而线程里不会,等 io 的时候它会让渡控制权。

再比如线程里面对字段或者全局变量的访问需要上锁,因为有调度,qtimer 就不用。

单核上的线程也是线程,不能假设它是严格串行的。
XIVN1987
2018-02-01 13:15:19 +08:00
@wizardforcel

多谢,这点我已经理解了!!

我现在的想法是:执行时间短的操作用 QTimer,可以直接操作主线程里的界面元素,方便;执行时间长的操作用线程,不会卡死界面

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/427395

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX