Python解决多进程间访问效率低的方法总结
作者:剑客阿良_ALiang 发布时间:2023-11-25 11:57:43
前言
最近在解决一些算法优化的问题,为了实时性要求,必须精益求精的将资源利用率用到极致。同时对算法中一些处理进行多线程或者多进程处理。
在对代码的调试过程中,发现在进程间队列使用耗时很长,特别是图片这种比较大的数据的时候。
可以先看一下我下面的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
时间间隔还是比较稳定的。
来源:https://blog.csdn.net/zhiweihongyan1/article/details/126851924
猜你喜欢
- 1 集合集合可以使用大括号({})或者set()函数进行创建,但是创建一个空集合必须使用set()函数,而不能用{},大括号是用来创建一个空
- 前言在 Go 单元测试这个系列的第二部分 数据库的Mock测试 中我们介绍了用 go-sqlmock 给数据库的 CRUD 操作做Mock
- scriptlet的使用jsp页面中分三种scriptlet:第一种:<% %> 可以在里面写java的代码。定义java变量以
- 在 Python 2 中 xrange() 创建迭代对象的用法是非常流行的。比如: for 循环或者是列表/集合/字典推导式。这个表现十分像
- Div的浮动+循环(描述的不清楚,请看图)在设计和布局的时候,碰到图片循环问题,碰到间距问题,怎么样让循环的图片每行的起始点跟上边的titl
- 以下保存成 App.xml , 与asp文件放在相同目录下! 代码如下: <?xml version="1.0"
- 从信息组织角度来看,段落内行之间的关系要比段落之间的关系低一个级别,所以在呈现上段落之间的“段距”应该大于段落之内的“行距”,如此才能一目了
- 在上一篇文章中,我介绍了MySQL对XML支持的部分功能,包括--xml命令行选项,以及MySQL 5.1.5中开始引入的新功能。今天我将介
- JavaScript是一门OOP,而有些人说,JavaScript是基于对象的。1) 如何创建对象:1. 使用constructor,例如:
- 内容摘要:当讨论Request对象内容时,要研究的集合之一就是ServerVariables集合。这个集合包含了两种值的结合体,一种是随同页
- 我们小组讨论的话题是tab(标签)在使用时的禁忌。在讨论的开始,大家很快产生了六个感兴趣的话题:如何处理海量的tab?在浏览器中关掉tab之
- 来自巴西的设计师Roger Oddone的作品,通过此作品你可以了解到logo的设计的一些思路。
- 前几天,看到有人写了个superLink的东东,主要的做什么用呢?我们有时会给在大块元素加个window.location='htt
- 1. 导入包我们这次的任务是随机生成一些离散的点,然后用直线(y = w *x + b )去拟合首先看一下我们需要导入的包有torch 包为
- 1.获取所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 2.获取所有
- table通过使用下面语句创建:create table userinfo(name text, email text)更快地插入数据在此用
- 代码如下:'============================== '格式化HTML,SDCMS加强版 '==
- 如下所示:#先下载psutil库:pip install psutilimport psutilimport os,datetimedef
- 解决方式一:import matplotlib#1. 获取matplotlibrc文件所在路径matplotlib.matplotlib_f
- 前言matplotlib.pyplot是一些命令行风格函数的集合,使matplotlib以类似于MATLAB的方式工作。每个pyplot函数