如何在Python中实现无阻塞无限循环

时间:2019-02-19 12:13:50

标签: python loops asynchronous python-multithreading coroutine

我有一个无限循环,可以从网络摄像头读取视频帧,并且每个帧都会经过一个复杂的功能,需要很高的计算能力。因此,在显示帧时,由于阻塞代码,该程序会有些滞后。

我现在打算做的是

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

我已经测量了摄像头每秒捕获的帧数,即〜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

我的概念正确吗?还是我需要做其他类似协程的事情?

1 个答案:

答案 0 :(得分:1)

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

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

基本上,您将整个任务发送给由rq工作程序执行的并行进程。

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

请参阅具有上面用于发送作业的队列名称的命令。
希望对您有所帮助。