How to kill a process using the multiprocessing module?

杀马特。学长 韩版系。学妹 提交于 2019-12-10 16:17:11

问题


I have a process that is essentially just an infinite loop and I have a second process that is a timer. How can I kill the loop process once the timer is done?

def action():
  x = 0
  while True:
      if x < 1000000:
          x = x + 1
      else:
          x = 0

def timer(time):
  time.sleep(time)
  exit()    

loop_process = multiprocessing.Process(target=action)
loop_process.start()
timer_process = multiprocessing.Process(target=timer, args=(time,))
timer_process.start()

I want the python script to end once the timer is done.


回答1:


You could do it by using a sharing state between the processes and creating a flag value that all the concurrent processes can access (although this may be somewhat inefficient).

Here's what I'm suggesting:

import multiprocessing as mp
import time

def action(run_flag):
    x = 0
    while run_flag.value:
        if x < 1000000:
            x = x + 1
        else:
            x = 0

    print('action() terminating')


def timer(run_flag, secs):
    time.sleep(secs)
    run_flag.value = False


if __name__ == '__main__':

    run_flag = mp.Value('I', True)

    loop_process = mp.Process(target=action, args=(run_flag,))
    loop_process.start()

    timer_process = mp.Process(target=timer, args=(run_flag, 2.0))
    timer_process.start()

    loop_process.join()
    timer_process.join()

    print('done')



回答2:


A simple return statement after else in action() would work perfectly. Moreover, you had an error in your timer function. Your argument had the same name as inbuilt library time.

def action():
   x = 0
   while True:
      if x < 1000000:
         x = x + 1
      else:
         x = 0
         return # To exit else it will always revolve in infinite loop

def timer(times):
   time.sleep(times)
   exit()    

loop_process = multiprocessing.Process(target=action)
loop_process.start()
timer_process = multiprocessing.Process(target=timer(10))
timer_process.start()

Hope this answers your question!!!




回答3:


I think you don't need to make a second process just for a timer.

Graceful Timeout

In case you need clean up before exit in your action process, you can use a Timer-thread and let the while-loop check if it is still alive. This allows your worker process to exit gracefully, but you'll have to pay with reduced performance because the repeated method call takes some time. Doesn't have to be an issue if it' s not a tight loop, though.

from multiprocessing import Process
from datetime import datetime
from threading import Timer


def action(runtime, x=0):
    timer = Timer(runtime, lambda: None)  # just returns None on timeout
    timer.start()
    while timer.is_alive():
        if x < 1_000_000_000:
            x += 1
        else:
            x = 0

if __name__ == '__main__':

    RUNTIME = 1

    p = Process(target=action, args=(RUNTIME,))
    p.start()
    print(f'{datetime.now()} {p.name} started')
    p.join()
    print(f'{datetime.now()} {p.name} ended')

Example Output:

2019-02-28 19:18:54.731207 Process-1 started
2019-02-28 19:18:55.738308 Process-1 ended

Termination on Timeout

If you don't have the need for a clean shut down (you are not using shared queues, working with DBs etc.), you can let the parent process terminate() the worker-process after your specified time.

terminate()

Terminate the process. On Unix this is done using the SIGTERM signal; on Windows TerminateProcess() is used. Note that exit handlers and finally clauses, etc., will not be executed.

Note that descendant processes of the process will not be terminated – they will simply become orphaned.

Warning If this method is used when the associated process is using a pipe or queue then the pipe or queue is liable to become corrupted and may become unusable by other process. Similarly, if the process has acquired a lock or semaphore etc. then terminating it is liable to cause other processes to deadlock. docs

If you don't have anything to do in the parent you can simply .join(timeout) the worker-process and .terminate() afterwards.

from multiprocessing import Process
from datetime import datetime

def action(x=0):
    while True:
        if x < 1_000_000_000:
            x += 1
        else:
            x = 0

if __name__ == '__main__':

    RUNTIME = 1

    p = Process(target=action)
    p.start()
    print(f'{datetime.now()} {p.name} started')
    p.join(RUNTIME)
    p.terminate()
    print(f'{datetime.now()} {p.name} terminated')

Example Output:

2019-02-28 19:22:43.705596 Process-1 started
2019-02-28 19:22:44.709255 Process-1 terminated

In case you want to use terminate(), but need your parent unblocked you could also use a Timer-thread within the parent for that.

from multiprocessing import Process
from datetime import datetime
from threading import Timer

def action(x=0):
    while True:
        if x < 1_000_000_000:
            x += 1
        else:
            x = 0


def timeout(process, timeout):
    timer = Timer(timeout, process.terminate)
    timer.start()


if __name__ == '__main__':

    RUNTIME = 1

    p = Process(target=action)
    p.start()
    print(f'{datetime.now()} {p.name} started')
    timeout(p, RUNTIME)
    p.join()
    print(f'{datetime.now()} {p.name} terminated')

Example Output:

2019-02-28 19:23:45.776951 Process-1 started
2019-02-28 19:23:46.778840 Process-1 terminated


来源:https://stackoverflow.com/questions/54929482/how-to-kill-a-process-using-the-multiprocessing-module

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!