【问题标题】:How to implement non-blocking infinite loop in Python如何在 Python 中实现非阻塞无限循环
【发布时间】:2019-02-19 12:13:49
【问题描述】:

我有一个无限循环,从网络摄像头读取视频帧,每一帧都将通过一个需要高计算能力的复杂函数。因此,当显示帧时,由于阻塞代码,程序会感觉有点迟钝。

我现在打算做的是,

  • 只收集目标对象出现时的前几帧
  • 将它们放到一个单独的线程中以避免代码阻塞。

我测量了网络摄像头每秒捕获的帧数,大约为 28 帧。所以每秒while循环只会收集前5帧并在另一个线程中处理它们,并在所有5个函数完成后返回结果。

我尝试使用“Pool”和“Queue”但无法正常工作,循环仍然被阻塞。下面的代码模糊地代表了我的程序现在的样子,我回家后将对其进行编辑,现在使用电话发布。

def detect(frame):
    # detect target object from images
    pass

def nn(frame):
    # some heavy processing code
    pass

count = 0
stack = []

while True:
    frame = cv2.imread(0)

    detected = detect(frame)

    # stop collecting images when collected 5
    if detected and count <= 5:
        stack.append(frame)
        count += 1

    # start processing
    if len(stack) == 5:
        p = Pool(4)
        results = p.map(nn, frame)
        p.close()
        p.join()

        # reset
        stack = []
        count = 0

我的概念正确吗?或者我需要做一些其他的事情,比如协程?

【问题讨论】:

标签: python loops asynchronous python-multithreading coroutine


【解决方案1】:

我使用rq解决了这个问题。
一个简单的python消息队列。 首先,实现你需要异步运行的方法。

它将运行您的 nn 函数,在这种情况下,
然后,为消息队列设置一个简单的配置, 我使用redis 包中的connectionPool。

基本上,您将整个任务发送到由 rq worker 执行的并行进程。

def nn(frame):
    # some heavy processing code
    pass

def asynch_call(frame):
   p = Pool(4)
   results = p.map(nn, frame)
   p.close()
   p.join()

pool = redis.ConnectionPool(
  host=HOST, 
  port=PORT, 
  password=PASS, 
  db=0)

r = redis.Redis(connection_pool=pool)  
q = Queue('nn_queue', connection=r)

count = 0
stack = []

while True:
    frame = cv2.imread(0)

    detected = detect(frame)

    # stop collecting images when collected 5
    if detected and count <= 5:
        stack.append(frame)
        count += 1

    # start processing
    if len(stack) == 5:

        job = q.enqueue(asynch_call, frame, timeout=any_long_timeout )

        if job.status=='queued':
            print("Job submission ok")

            # reset
            stack = []
            count = 0

为了启动一个处理异步调用的工作线程,您有几个选择,为Worker 创建自己的代码,或者在单独的终端中运行以下命令:

rq worker nn_queue

查看上面用于发送作业的带有队列名称的命令。
希望对你有帮助。

【讨论】:

  • 我修正了一点答案。祝你好运!
  • 谢谢。有点出乎原来的问题,但是 rq 的 Queue 和 python 本身的 Queue 有什么区别?
  • 嗯,总的来说可能是一样的。 Rq 在 Redis 之上。与 Python Queue 的纯实现相比,Rq 可以更简单地与您当前的设计集成。
  • 首先,您的回答效果很好!我已经通过您的实现实现了非阻塞代码。其次,通过使用队列,这是否意味着我所有的帧都将被顺序处理?如果是,我怎样才能通过并行化这个过程来加快速度?
  • 您仍然需要同时使用 python 队列 + 多线程。无论如何,请记住,大量线程共享内存有很多问题。正如你所做的那样,这是非常正确的。相反,为了更快的速度,运行单独的进程(并行)在消息队列中注入帧,然后消费者asynch_call从队列中提取帧并使用多线程p.map(nn, frame)处理它们。离你现在的位置不远。
猜你喜欢
  • 2018-03-27
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
  • 2017-12-15
  • 2022-08-20
相关资源
最近更新 更多