简体   繁体   English

如何在python中的无限循环中终止进程?

[英]How do I terminate processes in an infinite loop in python?

I have to write a code that converts video files from RGB to black and white using an equation that converts every frame to black and white. 我必须编写一个代码,使用公式将每一帧都转换为黑白,从而将视频文件从RGB转换为黑白。 and I have to do that in parallel with multiprocessing and queue and with the help of Opencv. 而且我必须在多处理和队列的同时并借助Opencv做到这一点。 I did write the code but I have a problem with the termination of the processes in the infinite loop. 我确实编写了代码,但是在无限循环中终止进程存在问题。 How can I terminate the processes when I am finished with reading the frames, because the father is waiting for the children to finish and they never finish. 读完框架后,我如何终止进程,因为父亲正在等待孩子完成任务,而他们从未完成任务。 this is my code.. 这是我的代码。

#! /usr/bin/python
import numpy as np
import cv2
import multiprocessing as mp
import time


def read_frames(q1, q2):
    while True:
        NumAndFrame = q1.get()
        frame = NumAndFrame[1]
        if frame == 'Done':
            # Here is my problem,this is not working!!!
            processes.terminate()
            break
        j = NumAndFrame[0]
        R = frame[:, :, 0]
        G = frame[:, :, 1]
        B = frame[:, :, 2]
        y = (np.uint8)((0.299 * R) + (0.587 * G) + (0.114 * B))
        q2.put((j, y))



if __name__ == '__main__':
    start = time.time()
    q1 = mp.Queue()
    q2 = mp.Queue()
    processes = []
    for i in range(4):
        processes.append(mp.Process(target=read_frames, args=(q1, q2)))
    for p in processes:
        p.start()

    # feed the processes
    # read input file and send to the processes the frames:
    cap = cv2.VideoCapture('gou.avi')
    lines = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    cols = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    fourcc_ver = int(cap.get(cv2.CAP_PROP_FOURCC))
    out = cv2.VideoWriter('output.avi', fourcc_ver, fps, (cols, lines), False)

    j = 1
    while (cap.isOpened()):
        ret, frame = cap.read()
        # as long as new frames are there
        if ret == True:
            q1.put((j, frame))
            j += 1
        # if cv2.waitKey(1) & 0xFF == ord('q'):
        #   break
        else:
            break

q1.put((1, 'Done'))
for p in processes:
    p.join()
result = []
for p in processes:
    result.append(q2.get())
result.sort()
result = []
for r in result:
    result.append(r[1])
for i in result:
    out.write(i)
    print i
# Release everything if job is finished
print 'final finish'
cap.release()
out.release()
cv2.destroyAllWindows()

You might want to try to pair your question down to a smaller example, but if you're just interested in stopping the computation in the middle of a loop that is running indefinitely, you can spam Ctrl-C until it halts. 您可能希望尝试将问题与一个较小的示例配对,但是如果您只想在无限期运行的循环中间停止计算,则可以向Ctrl-C发出垃圾邮件,直到它停止为止。 Alternatively, you can just close the shell window. 或者,您可以仅关闭外壳程序窗口。

Without having tested, for the same reason others gave in there comments: You should rather call "terminate" on each process within the main part, than call it in the child function: 无需测试,出于相同的原因,其他人在其中进行了评论:您应该宁可在主体部分的每个进程上调用“终止”,也不应该在子函数中调用它:

 ...
for p in processes:
    p.terminate()
    p.join()

Consider using multiprocessing.Pool because it does most of the heavy lifting for you. 考虑使用multiprocessing.Pool,因为它可以为您完成大部分繁重的工作。

You need a "done" message for each child process. 每个子进程都需要一条“完成”消息。 The child should send some sort of acknowledgement back to the parent and terminate. 孩子应将某种确认发送回父母并终止。 You also need some sort of error handling policy in the worker so that an exception doesn't just silently exit the worker. 您还需要在工作程序中使用某种错误处理策略,以使异常不会仅以静默方式退出工作程序。

You have other problems such as this code that confuses number of processes with number of messages processed. 您还有其他问题,例如此代码使进程数与已处理消息数混淆。

for p in processes:
    result.append(q2.get())

Instead you should read all messages, counting the number of termination acknowledgements it gets on the way so that you know when to stop reading. 相反,您应该阅读所有消息,计算其途中收到的终止确认的数量,以便知道何时停止阅读。

Your script is long and I'm not going to pretend that I've gotten it all right (please be friendly and post smaller examples in the future!) but here is a first go at cleaning it up. 您的脚本很长,我不会假装一切都正确(请友好并且将来发布更小的示例!),但是这是清理它的第一步。

#! /usr/bin/python
import numpy as np
import cv2
import multiprocessing as mp
import time


def read_frames(q1, q2):
    while True:
        try:
            NumAndFrame = q1.get()
            frame = NumAndFrame[1]
            if frame == 'Done':
                q2.put('Done')
                break
            j = NumAndFrame[0]
            R = frame[:, :, 0]
            G = frame[:, :, 1]
            B = frame[:, :, 2]
            y = (np.uint8)((0.299 * R) + (0.587 * G) + (0.114 * B))
            q2.put((j, y))
        except Exception, e:
            q2.put('Error: ' + str(e))


if __name__ == '__main__':
    start = time.time()
    q1 = mp.Queue()
    q2 = mp.Queue()
    processes = []
    for i in range(4):
        processes.append(mp.Process(target=read_frames, args=(q1, q2)))
    for p in processes:
        p.start()

    # feed the processes
    # read input file and send to the processes the frames:
    cap = cv2.VideoCapture('gou.avi')
    lines = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    cols = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    fourcc_ver = int(cap.get(cv2.CAP_PROP_FOURCC))
    out = cv2.VideoWriter('output.avi', fourcc_ver, fps, (cols, lines), False)

    j = 1
    while (cap.isOpened()):
        ret, frame = cap.read()
        # as long as new frames are there
        if ret == True:
            q1.put((j, frame))
            j += 1
        # if cv2.waitKey(1) & 0xFF == ord('q'):
        #   break
        else:
            break

for _ in len(processes):
    q1.put((1, 'Done'))
for p in processes:
    p.join()
result = []
done_count = 0
while done_count < len(processes):
    data = q2.get()
    if isinstance(data, basetring) and data == 'Done':
        done_count += 1
    else:
        result.append(data)

result.sort()

# What??? don't overwrite result here!
result = []
for r in result:
    result.append(r[1])
for i in result:
    out.write(i)
    print i
# Release everything if job is finished
print 'final finish'
cap.release()
out.release()
cv2.destroyAllWindows()

You end up holding the entire returned dataset in the parent so you may hit memory problems. 您最终将整个返回的数据集保存在父级中,因此可能遇到内存问题。 And since (1) you have a large data payload being copied from parent to child and back, and (2) numpy releases the gil, you may find threads perform better than processes. 而且,由于(1)您有一个很大的数据有效负载要从父级复制到子级,然后再返回,并且(2)numpy释放gil,因此您可能会发现线程的性能优于进程。 You can check rather quickly by just substituting Thread for Process when you create the workers. 您可以通过在创建工作Thread时仅将Thread替换为Process来快速检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM