簡體   English   中英

如何使用 Python 和 Windows 中的多處理從子進程中殺死父進程?

[英]How can I kill a parent from a child process using multiprocessing in Python and Windows?

我想在其中一個子進程到達特定點時結束我的腳本。 假設我有以下代碼:

import multiprocessing
import time
import sys


def another_child_process (my_queue):
    time.sleep(3)
    my_queue.put("finish")

def my_process(my_queue):
    while True:
        if my_queue.empty() is False:
            my_queue.get()
            print("Killing the program...")
            ### THIS IS WHERE I WANT TO KILL MAIN PROCESS AND EXIT
            sys.exit(0) 


def main():

    ## PARENT PROCESS WHICH I WANT TO KILL FROM THE CHILD

    my_queue = multiprocessing.Queue()

    child_process = multiprocessing.Process(target=my_process, args=(my_queue,))
    another_process = multiprocessing.Process(target=another_child_process, args=(my_queue,))

    child_process.start()
    another_process.start()

    while True:
        pass ## I want to end the program in the child process

       
if __name__=="__main__":
    main()

我讀過一些關於使用信號的東西,但它們主要用於 Linux,我不太清楚如何在 Windows 中使用它們。 實際上,我是 Python 的初學者。 我怎樣才能完全結束腳本?

首先,如果你仔細閱讀文檔,你會發現在multiprocessing.Queue上調用is_empty方法是不可靠的,不應該使用。 此外,你有一個競爭條件 也就是說,如果my_processanother_child_process之前運行(並且假設is_empty是可靠的),它會發現隊列為空並提前終止,因為another_child_process還沒有機會將任何項目放入隊列。 所以你應該做的是讓another_child_process將它想要的任何消息放在隊列中,然后放置一個額外的哨兵項目,其目的是表明沒有更多的項目將被放入隊列。 因此,哨兵用作准文件結束指示器。 您可以使用任何不同的對象作為哨兵,只要它不能被視為“真實”數據項。 在這種情況下,我們將使用None作為哨兵。

但是您編寫的實際示例並不是一個實際示例,說明為什么您需要一些特殊機制來終止主進程並退出,因為一旦another_process將其項目放入隊列中,它就會返回並因此進程終止並且一旦my_process檢測到它已經從隊列中檢索了所有項目並且將不再有,它返回並因此其進程終止。 因此,主進程所要做的就是發出一個調用以join兩個子進程並等待它們完成然后退出:

import multiprocessing
import time
import sys

def another_child_process (my_queue):
    time.sleep(3)
    my_queue.put("finish")
    my_queue.put(None)

def my_process(my_queue):
    while True:
        item = my_queue.get()
        if item is None:
            break
        print('Item:', item)


def main():

    ## PARENT PROCESS WHICH I WANT TO KILL FROM THE CHILD

    my_queue = multiprocessing.Queue()

    child_process = multiprocessing.Process(target=my_process, args=(my_queue,))
    another_process = multiprocessing.Process(target=another_child_process, args=(my_queue,))

    child_process.start()
    another_process.start()

    child_process.join()
    another_process.join()


if __name__=="__main__":
    main()

印刷:

Item: finish

這里也許是一個更好的例子。 another_child_process以某種方式獲取數據(出於演示目的,我們有一個生成器函數get_data )。 如果沒有出現異常情況,它會將所有數據放入隊列中,以便my_process跟隨None哨兵項,以便my_process知道沒有更多數據即將到來,它可以終止。 但是讓我們假設get_data有可能生成一個特殊的異常數據項,即用於演示目的的字符串“finish”。 在這種情況下, another_child_process將立即終止。 但是,此時隊列中有許多項my_process尚未檢索和處理。 我們想強制my_process立即終止,以便主進程可以立即join子進程並終止。

為此,我們將一個事件傳遞給由主進程啟動的守護線程,該線程等待事件被設置。 如果事件是由another_child_process設置的,我們也將事件傳遞給了它,線程將立即終止my_process進程:

import multiprocessing
import time
import sys

def get_data():
    for item in ['a', 'b', 'c', 'finish', 'd', 'e', 'f', 'g']:
        yield item

def another_child_process(my_queue, exit_event):
    for item in get_data():
        if item == 'finish':
            # Abnormal condition where we must exit imemediately.
            # Immediately signal main process terminate:
            exit_event.set()
            # And we terminate:
            return
        my_queue.put(item)
    # Normal situation where we just continue
    # Put in sentinel signifying no more data:
    my_queue.put(None)

def my_process(my_queue):
    while True:
        item = my_queue.get()
        if item is None: # Sentinel?
            # No more data:
            break
        print("Got: ", repr(item))
    print('my_process terminating normally.')

def main():
    import threading

    def wait_for_quit(exit_event):
        nonlocal child_process

        exit_event.wait()
        child_process.terminate()
        print("Exiting because event was set.")

    exit_event = multiprocessing.Event()

    # Start daemon thread that will wait for the quit_event
    threading.Thread(target=wait_for_quit, args=(exit_event,), daemon=True).start()

    my_queue = multiprocessing.Queue()
    child_process = multiprocessing.Process(target=my_process, args=(my_queue,))
    another_process = multiprocessing.Process(target=another_child_process, args=(my_queue, exit_event))

    child_process.start()
    another_process.start()

    # Wait for processes to end:
    child_process.join()
    another_process.join()


if __name__=="__main__":
    main()

印刷:

Got:  'a'
Exiting because event was set.

如果您從get_data返回的數據中刪除finish消息,則所有進程將正常完成,打印的內容將是:

Got:  'a'
Got:  'b'
Got:  'c'
Got:  'd'
Got:  'e'
Got:  'f'
Got:  'g'
my_process terminating normally.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM