Python解决多进程间访问效率低的方法总结
前言
最近在解决一些算法优化的问题,为了实时性要求,必须精益求精的将资源利用率用到极致。同时对算法中一些处理进行多线程或者多进程处理。
在对代码的调试过程中,发现在进程间队列使用耗时很长,特别是图片这种比较大的数据的时候。
可以先看一下我下面的demo是不是符合你的场景。
下面还有我的解决方案。
使用进程间Queue效率问题场景
代码样例如下,模拟从两个视频读取图片帧进行处理。
#!/user/bin/env python # coding=utf-8 """ @project : csdn-pro @author : 剑客阿良_ALiang @file : test13.py @ide : PyCharm @time : 2022-09-13 10:47:35 """ import time import cv2 from multiprocessing import Queue, Process def fun1(q: Queue): cap = cv2.VideoCapture("11.mp4") a = [] while cap.isOpened(): ret, frame = cap.read() if ret: a.append(frame) if len(a) == 25: q.put(a) a = [] time.sleep(0.038) def fun2(q: Queue): cap = cv2.VideoCapture("3333333.mp4") a = [] while cap.isOpened(): ret, frame = cap.read() if ret: a.append(frame) if len(a) == 25: q.put(a) a = [] time.sleep(0.038) def fun3(q1: Queue, q2: Queue, q3: Queue): while True: st0 = time.time() a1 = q1.get() st1 = time.time() a2 = q2.get() st2 = time.time() print("{} 耗时:{} - {}".format(time.time(), st1 - st0, st2 - st1)) q3.put((a1, a2)) def fun4(q3: Queue): while True: st0 = time.time() a1, a2 = q3.get() et = time.time() print("hhhh耗时: {}".format(et - st0)) if __name__ == '__main__': q1 = Queue() q2 = Queue() q3 = Queue() p1 = Process(target=fun1, args=(q1,)) p2 = Process(target=fun2, args=(q2,)) p3 = Process(target=fun3, args=(q1, q2, q3,)) p4 = Process(target=fun4, args=(q3,)) p1.start() p2.start() p3.start() p4.start() p1.join() p2.join() p3.join() p4.join()
代码说明:
1、上面模拟每秒25帧读取图片,并传递一个25帧的图片list给到队列。
我们看一下从queue获取图片list的效率。部分执行结果如下。
1663139091.3648114 耗时:1.6036181449890137 - 0.1361703872680664
hhhh耗时: 3.0635826587677
1663139093.056612 耗时:1.5302414894104004 - 0.1615591049194336
hhhh耗时: 1.6867034435272217
1663139094.7388775 耗时:1.5256507396697998 - 0.1566147804260254
hhhh耗时: 1.6849782466888428
1663139096.36547 耗时:1.4680161476135254 - 0.15857625007629395
hhhh耗时: 1.651228427886963
1663139097.9867501 耗时:1.4417593479156494 - 0.179520845413208
hhhh耗时: 1.609663963317871
1663139099.5894623 耗时:1.4391484260559082 - 0.16356372833251953
hhhh耗时: 1.7086796760559082
1663139101.3031366 耗时:1.5481102466583252 - 0.16556406021118164
hhhh耗时: 1.657604455947876
1663139102.9448056 耗时:1.470097303390503 - 0.1715717315673828
hhhh耗时: 1.5316739082336426
1663139104.5233243 耗时:1.4139580726623535 - 0.16456055641174316
Process finished with exit code -1
可以看出我们从进程队列get数据的耗时很长,从q3中同时获取的时间如蓝色标记,远大于1秒钟。
而整体获取图片帧的效率如红色标记,间隔时间大于1秒。
采用管道模式解决
这个时间间隔没法接受,我才用multiprocessing.Pipe管道来提前输入图片。
样例代码如下:
#!/user/bin/env python # coding=utf-8 """ @project : csdn-pro @author : 剑客阿良_ALiang @file : test13.py @ide : PyCharm @time : 2022-09-13 10:47:35 """ import threading import time import cv2 from multiprocessing import Queue, Process, Pipe def fun1(pipe_in): cap = cv2.VideoCapture("11.mp4") while cap.isOpened(): ret, frame = cap.read() if ret: ret, frame = cap.read() pipe_in.send((int(time.time()), frame)) time.sleep(0.038) def fun2(pipe_in): cap = cv2.VideoCapture("3333333.mp4") while cap.isOpened(): ret, frame = cap.read() if ret: ret, frame = cap.read() pipe_in.send((int(time.time()), frame)) time.sleep(0.038) def fun3(pipe_rev1, pipe_rev2): def handle(pipe_rev1, q1): _cul = 0 a = [] while True: _t, _frame = pipe_rev1.recv() if _cul == 0: a.append(_frame) _cul = _t elif _t > _cul != 0: if len(a) != 0: q1.put(a) _cul = _t a = [] a.append(_frame) elif _t == _cul != 0: a.append(_frame) q1 = Queue() q2 = Queue() threading.Thread(target=handle, args=(pipe_rev1, q1,)).start() threading.Thread(target=handle, args=(pipe_rev2, q2,)).start() while True: if not q1.empty() and not q2.empty(): st0 = time.time() _f1 = q1.get() st1 = time.time() _f2 = q2.get() et = time.time() print("{} 耗时:{} - {}".format(time.time(), st1 - st0, et - st1)) if __name__ == '__main__': pipe_in1, pipe_out1 = Pipe() pipe_in2, pipe_out2 = Pipe() p1 = Process(target=fun1, args=(pipe_in1,)) p2 = Process(target=fun2, args=(pipe_in2,)) p3 = Process(target=fun3, args=(pipe_out1, pipe_out2,)) p1.start() p2.start() p3.start() p1.join() p2.join() p3.join()
代码说明:
1、通过两个线程不停从管道接受并写到内存的Queue里面,提前放到当前进程内存里。
看一下间隔是否稳定,部分执行结果如下
1663139886.0722673 耗时:0.003930091857910156 - 0.005983591079711914
1663139887.6837587 耗时:0.09677457809448242 - 0.09172177314758301
1663139888.472634 耗时:0.061833858489990234 - 0.05984067916870117
1663139889.5441313 耗时:0.07132482528686523 - 0.07080578804016113
1663139890.548978 耗时:0.06183457374572754 - 0.06881546974182129
1663139891.5112402 耗时:0.0637204647064209 - 0.0718080997467041
1663139892.4756596 耗时:0.06682205200195312 - 0.06978344917297363
1663139893.5788367 耗时:0.06779074668884277 - 0.07928323745727539
时间间隔还是比较稳定的。
总结
如果你遇到和我一样的场景,可以仔细观察一下进程间数据是否传输的比较慢。可以考虑和我一样的方式来解决。
到此这篇关于Python解决多进程间访问效率低的方法总结的文章就介绍到这了,更多相关Python多进程访问效率低内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
python dataframe astype 字段类型转换方法
下面小编就为大家分享一篇python dataframe astype 字段类型转换方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2018-04-04python实现三种字符串格式化方法(%、format、f-string)
本文主要介绍了python实现三种字符串格式化方法,主要包括%、format、f-string,具有一定的参考价值,感兴趣的可以了解一下2023-10-10
最新评论