1
coolrice1 2020-10-13 17:57:46 +08:00
QRunnable 和 QThreadPool 可以用吗?
|
3
lyhapple 2020-10-13 18:14:47 +08:00
如果是 python3, 为什么不用协程?
|
4
lpts007 2020-10-13 18:26:21 +08:00
"而且我在 UI 线程中没有办法创建多进程就很蛋疼" 这句话怎么回事,是你写错了吧!
很多年前我写的小东西,启动 ui,其中几个按钮是长耗时功能(查数据库,长时间计算),就是点击以后用多进程进行的计算的,没啥问题啊。 |
5
ytymf 2020-10-13 18:30:23 +08:00
可以把你的计算任务与 QT 界面完全的解耦,独立启动。二者通过 socket 或者 pipe 通信就好了。没有必要非要当成一个工程。
|
6
jin7 2020-10-13 18:31:19 +08:00
楼上说得在理
|
8
menc 2020-10-13 18:32:02 +08:00
拆分两个项目,rpc 调用即可
|
9
gangdong OP @lpts007
或许是我的问题?我在 qt 的 ui 线程里面确实没有办法创建其他的进程(逻辑上进程不是比线程更高一个层次吗) |
14
jin7 2020-10-13 18:37:48 +08:00
你搞不定的话 可付费帮你搞定 刚帮人搞定了一样的问题 不喜忽视
|
17
renmu123 2020-10-13 18:44:00 +08:00 via Android
gill 是没办法利用多核,只是多线程是伪多线程,出来 io 阻塞没有问题
|
19
ClutchBear 2020-10-13 18:53:29 +08:00
flask 后端,
vue 前端 gunicorn 开多个进程, 也不慢的. |
20
knightdf 2020-10-13 19:28:15 +08:00
> 而且我在 UI 线程中没有办法创建多进程就很蛋疼。
可以用啊, 我写过一个小软件就是 qt+multiprocessing |
21
AX5N 2020-10-13 20:01:30 +08:00
我觉得和 c 混编比较好,就看你有没有能力把重计算部分用 c 来写了。根据你项目的复杂度的不同,不见得有必要一定要让 c 来完成多线程。cpu 密集型不建议纯 python,除非你换解释器,否则即便把 python 玩出花,2 30 倍的性能差距还是跑不掉的。
|
22
AX5N 2020-10-13 20:06:10 +08:00
@AX5N 调用 C 库很简单,你用 C 编写个函数,并且将这个函数导出来,然后用 python 去调用这个函数就行了。你可以在 python 上用多线程(协程)去调用这个函数,重活都丢给 c 去干。
|
24
gangdong OP @AX5N 是的老哥,我认真分析了我的程序,其中计算部分的一部分我使用 numpy 来完成的,这部分估计我写也不会比 numpy 更好。另一个需要计算的部分是无法避免的循环,循环的话,c 和 python 不知道是否有较大的性能差距,后面我测试一下。谢谢老哥的认真回复。
|
25
gangdong OP @ClutchBear 这样是一个思路,现在界面是使用 qt 做的,这条路行不通了,再试试这个。谢谢。
|
26
gladuo 2020-10-13 22:07:44 +08:00
混编的话搜索引擎关键词『 pybind11 』
|
27
gladuo 2020-10-13 22:09:28 +08:00
楼上说的方案就是你 1. 的方案,只不过界面还是沿用 pyqt 而不用换成 html,计算的部分独立作为服务就好
|
28
AX5N 2020-10-13 22:31:36 +08:00
@gangdong 据我所知,c 可以调用 numpy https://numpy.org/devdocs/user/c-info.html
|
30
gangdong OP @knightdf 目前我是在 ui 里使用 QThread 开一个线程进行计算,这个应该是线程没问题吧? 你的意思是在 QThread 这个新的线程里再开启多进程?
|
33
snowydec 2020-10-13 23:18:22 +08:00
建议先把版本升级到研三,应该就解决了
|
34
BingoXuan 2020-10-13 23:33:54 +08:00 via Android 1
我们公司架构就是 pyqt 启动界面时候开多进程做计算引擎,用 zmq 来做 ipc,非常简单方便
|
35
frankjoe 2020-10-14 00:22:37 +08:00 via Android
QRunnable 和 QThreadPool 可以用吗?
|
39
no1xsyzy 2020-10-14 10:15:30 +08:00
刚随便试了下,除了用 QTimer 非阻塞下了点功夫外没什么问题……
但发现一个坑点:请确保创建 GUI 的代码在 __name__ == '__main__' 下,以及不要拉升 Queue 的位置,一旦拉升就要 pickle,但 Queue 不能 pickle https://gist.github.com/no1xsyzy/03fb6d436dc3e87a1d2d12505d9234fe |
40
no1xsyzy 2020-10-14 10:25:24 +08:00
好像也不是拉升就要 pickle,刚才 p.start() 一直报 Queue 不能 pickle……
顺便修了下之前运行中再次点击按钮导致卡死的问题 |
42
iqxd 2020-10-14 14:53:56 +08:00
好像 windows 和 linux 下的 python 多进程是有些区别的,linux 的底层是 fork. 如果是调用了 numpy 做计算,用线程调用影响也没那么大吧,numpy 在 C 层面是会用到多核计算的.
|
44
E520 2020-10-14 18:32:02 +08:00
易语言
|
46
gangdong OP @knightdf 你好,我今天尝试了在 ui 线程里创建新的计算线程,然后在计算线程里开启多进程。还是有问题。
我查了一下,问题大概是:在 windows 上子进程 一定要放在 if __name__ == '__main__' 下面。 您当初的程序是在 windows 上开发的吗 |
47
BingoXuan 2020-10-14 22:24:44 +08:00 via Android
@gangdong
主进程先启动计算进程,然后进去界面 main 函数,等待界面 main 结束后就传递信号给计算进程结束任务,最后关闭所有资源。 |
48
gangdong OP |
49
no1xsyzy 2020-10-15 09:16:13 +08:00
|
51
gangdong OP @knightdf
import sys from PyQt5.QtWidgets import QMainWindow,QApplication,QWidget from untitled import * from PyQt5.QtWidgets import QFileDialog from multiprocessing import Pool from PyQt5.QtCore import QObject,pyqtSignal,QThread import time,os class LoadFiles(QObject): run_end=pyqtSignal() def __init__(self): super(LoadFiles, self).__init__() def run(self): testFL = [1, 2, 3, 4, 5, 6] pool = Pool(6) pool.apply_async(self.work) pool.close() pool.join() self.run_end.emit() def work(self): # fn: 函数参数是数据列表的一个元素 fn=100 print('当前进程: {}'.format(os.getpid()), time.time()) time.sleep(10) print(fn * fn) class PrecessTest(QMainWindow,Ui_MainWindow): def __init__(self): super(PrecessTest, self).__init__() self.setupUi(self) self.pushButton.clicked.connect(self.load_files) def load_files(self): self._loadThread=QThread() self.loadThread=LoadFiles() self.loadThread.run_end.connect(self.stop_thread) self.loadThread.moveToThread(self._loadThread) self._loadThread.started.connect(self.loadThread.run) # openfile_name = QFileDialog.getOpenFileNames(self,'选择文件',"./","TDMS Files(*.tdms)") # print(openfile_name) self._loadThread.start() print('现在线程状态 :', self._loadThread.isRunning()) def stop_thread(self): self._loadThread.quit() self._loadThread.wait() print('现在线程状态 :', self._loadThread.isRunning()) if __name__ == '__main__': app=QApplication(sys.argv) ui=PrecessTest() ui.show() sys.exit(app.exec_()) 你好,我简单的写了一下,这样的话就是不能开多进程,因为开启多进程的部分在 windows 上应该在__main__:的下面,我就不知道如何操作了,主要的问题应该是在子线程下面无法创建多进程? 我是新人,没办法使用 gist 添加外部链接不好意思。。。 |
52
gangdong OP @no1xsyzy
能麻烦看看我上面的代码回复吗,我不知道如何让将创建进程池的部分代码放在 if __name__ == '__main__' 下面(为了避免 ui 堵塞,我得将计算部分新建一个线程,这样如何在这个新的线程中建立多进程呢...) |
54
knightdf 2020-10-15 13:10:17 +08:00
@gangdong 刚上 v2,我是 mac 下开发的,但是在 windows 上打包的,所以平台应该不影响。
没缩进太难看了,贴个你的示例吧 https://gist.github.com/knightdf/657b5418a9ec11ec1138464b37d1c14c 照你的逻辑手打的,可能 typo |
55
Asfy 2020-10-15 13:32:07 +08:00
和我毕业设计差不多啊
量化分析,pyqt 展示 跑个算法, 界面卡死. 要用 python, 直接分两个服务 数据和界面. 数据服务换语言写, 界面 python 搞, 甚至界面可以直接换掉. |
56
gangdong OP @Asfy 界面的话。qt pyqt 都差不多,你是说后台的数据处理换语言是吧,请问你用的什么写的😂
|
62
no1xsyzy 2020-10-15 22:33:17 +08:00
@gangdong ……找了一圈才发现有个网络剪贴板名字就叫“网络剪贴板” …… 其实是指 pastebin[.]com 和 paste.ubuntu[.]com 这些
还是先 https://stackoverflow.com/help/minimal-reproducible-example 吧 Pool 里不要传 bound method,会导致整个实例被 pickle,然而 QObject 不能被 pickle 把 LoadFiles.work 搞成 staticmethod 或者 classmethod 或者干脆提出去当作单独函数处理。 https://gist.github.com/no1xsyzy/ef171f987a2e78e5f831e523a14c7e9e#file-v2_714573_2-py-L30-L34 你得明白一点,multiprocessing 的基础是 pickle,一切内容都是 pickle 之后通过管道传递到新进程里面去再解开使用,所以参与计算的任何内容都必须可以被 pickle 。但你继承了 C++ 的对象 QObject,就导致了它不能被 pickle (准确地说,它封装了一个 Qt 的 QObject,所以 classmethod 尽管封了一个 QObject 进去但是可以 pickle,因为类本身只有 binding 没有实际的 C++ 层对象) 另外,还有一点就是非 fork() 的方式均会导致整个文件以其他的 __name__ 重新执行一遍,这就是为什么根据平台会要求 __name__ == '__main__',rev2 里我把 __name__ 在子进程打印出来了,你可以看下。 |
65
knightdf 2020-10-16 09:52:17 +08:00
@gangdong 那你参考下这个吧,给 windows 的 multiprocessing 打个 patch 试试
https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing |
66
gangdong OP |