当前位置:   article > 正文

Python 多进程间访问效率低,如何解决?_python if效率慢

python if效率慢

前言

最近在解决一些算法优化的问题,为了实时性要求,必须精益求精的将资源用到极致。同时对算法中一些多线程或者多进程处理。

在对代码的调试过程中,发现在进程间队列使用耗时很长,特别是图片这种比较大的数据的时候。

可以先看一下我下面的demo是不是符合你的场景。

下面还有我的解决方案。

使用进程间Queue效率问题场景

代码样例如下,模拟从两个视频读取图片帧进行处理。

  1. #!/user/bin/env python
  2. # coding=utf-8
  3. """
  4. @project : csdn-pro
  5. @author : 剑客阿良_ALiang
  6. @file : test13.py
  7. @ide : PyCharm
  8. @time : 2022-09-13 10:47:35
  9. """
  10. import time
  11. import cv2
  12. from multiprocessing import Queue, Process
  13. def fun1(q: Queue):
  14. cap = cv2.VideoCapture("11.mp4")
  15. a = []
  16. while cap.isOpened():
  17. ret, frame = cap.read()
  18. if ret:
  19. a.append(frame)
  20. if len(a) == 25:
  21. q.put(a)
  22. a = []
  23. time.sleep(0.038)
  24. def fun2(q: Queue):
  25. cap = cv2.VideoCapture("3333333.mp4")
  26. a = []
  27. while cap.isOpened():
  28. ret, frame = cap.read()
  29. if ret:
  30. a.append(frame)
  31. if len(a) == 25:
  32. q.put(a)
  33. a = []
  34. time.sleep(0.038)
  35. def fun3(q1: Queue, q2: Queue, q3: Queue):
  36. while True:
  37. st0 = time.time()
  38. a1 = q1.get()
  39. st1 = time.time()
  40. a2 = q2.get()
  41. st2 = time.time()
  42. print("{} 耗时:{} - {}".format(time.time(), st1 - st0, st2 - st1))
  43. q3.put((a1, a2))
  44. def fun4(q3: Queue):
  45. while True:
  46. st0 = time.time()
  47. a1, a2 = q3.get()
  48. et = time.time()
  49. print("hhhh耗时: {}".format(et - st0))
  50. if __name__ == '__main__':
  51. q1 = Queue()
  52. q2 = Queue()
  53. q3 = Queue()
  54. p1 = Process(target=fun1, args=(q1,))
  55. p2 = Process(target=fun2, args=(q2,))
  56. p3 = Process(target=fun3, args=(q1, q2, q3,))
  57. p4 = Process(target=fun4, args=(q3,))
  58. p1.start()
  59. p2.start()
  60. p3.start()
  61. p4.start()
  62. p1.join()
  63. p2.join()
  64. p3.join()
  65. 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管道来提前输入图片。

样例代码如下:

  1. #!/user/bin/env python
  2. # coding=utf-8
  3. """
  4. @project : csdn-pro
  5. @author : 剑客阿良_ALiang
  6. @file : test13.py
  7. @ide : PyCharm
  8. @time : 2022-09-13 10:47:35
  9. """
  10. import threading
  11. import time
  12. import cv2
  13. from multiprocessing import Queue, Process, Pipe
  14. def fun1(pipe_in):
  15. cap = cv2.VideoCapture("11.mp4")
  16. while cap.isOpened():
  17. ret, frame = cap.read()
  18. if ret:
  19. ret, frame = cap.read()
  20. pipe_in.send((int(time.time()), frame))
  21. time.sleep(0.038)
  22. def fun2(pipe_in):
  23. cap = cv2.VideoCapture("3333333.mp4")
  24. while cap.isOpened():
  25. ret, frame = cap.read()
  26. if ret:
  27. ret, frame = cap.read()
  28. pipe_in.send((int(time.time()), frame))
  29. time.sleep(0.038)
  30. def fun3(pipe_rev1, pipe_rev2):
  31. def handle(pipe_rev1, q1):
  32. _cul = 0
  33. a = []
  34. while True:
  35. _t, _frame = pipe_rev1.recv()
  36. if _cul == 0:
  37. a.append(_frame)
  38. _cul = _t
  39. elif _t > _cul != 0:
  40. if len(a) != 0:
  41. q1.put(a)
  42. _cul = _t
  43. a = []
  44. a.append(_frame)
  45. elif _t == _cul != 0:
  46. a.append(_frame)
  47. q1 = Queue()
  48. q2 = Queue()
  49. threading.Thread(target=handle, args=(pipe_rev1, q1,)).start()
  50. threading.Thread(target=handle, args=(pipe_rev2, q2,)).start()
  51. while True:
  52. if not q1.empty() and not q2.empty():
  53. st0 = time.time()
  54. _f1 = q1.get()
  55. st1 = time.time()
  56. _f2 = q2.get()
  57. et = time.time()
  58. print("{} 耗时:{} - {}".format(time.time(), st1 - st0, et - st1))
  59. if __name__ == '__main__':
  60. pipe_in1, pipe_out1 = Pipe()
  61. pipe_in2, pipe_out2 = Pipe()
  62. p1 = Process(target=fun1, args=(pipe_in1,))
  63. p2 = Process(target=fun2, args=(pipe_in2,))
  64. p3 = Process(target=fun3, args=(pipe_out1, pipe_out2,))
  65. p1.start()
  66. p2.start()
  67. p3.start()
  68. p1.join()
  69. p2.join()
  70. 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

时间间隔还是比较稳定的。

总结

如果你遇到和我一样的场景,可以仔细观察一下进程间数据是否传输的比较慢。可以考虑和我一样的方式来解决。

分享:

        人的一生有一个半童年。一个童年在自己小时候,而半个童年在自己孩子的小时候。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/189710
推荐阅读
相关标签
  

闽ICP备14008679号