如何使用多进程模块杀死一个进程?

5

我有一个进程,本质上只是一个无限循环,并且我有第二个进程作为计时器。一旦计时器完成,该如何终止循环进程?

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()

我希望这个Python脚本在计时器完成后能够结束。
3个回答

2
我认为你不需要为计时器单独创建第二个进程。
优雅的超时
如果您的“操作”进程需要在退出之前进行清理,则可以使用“Timer”线程,并让while循环检查其是否仍然存活。这允许您的工作进程优雅地退出,但您必须付出一些性能代价,因为重复的方法调用需要一些时间。不过,如果它不是一个紧密的循环,这并不是问题。
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')

示例输出:
2019-02-28 19:18:54.731207 Process-1 started
2019-02-28 19:18:55.738308 Process-1 ended

超时终止

如果您不需要进行干净的关闭(未使用共享队列,与数据库等交互),则可以让父进程在指定时间后终止()工作进程。

terminate()

终止进程。在Unix上,使用SIGTERM信号;在Windows上,使用TerminateProcess()。请注意,退出处理程序和finally子句等将不会执行。

请注意,进程的子孙进程不会被终止-它们只会变成孤儿进程。

警告:如果该方法在关联进程正在使用管道或队列时使用,则管道或队列可能会损坏,并且可能无法被其他进程使用。同样,如果进程已经获得了锁或信号量等,则终止进程可能会导致其他进程死锁。docs

如果父进程没有其他任务,您可以简单地.join(timeout)工作进程,然后.terminate()

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')

示例输出:
2019-02-28 19:22:43.705596 Process-1 started
2019-02-28 19:22:44.709255 Process-1 terminated

如果你想使用 terminate(),但需要让父进程解除阻塞,你也可以在父进程中使用一个 Timer 线程来实现。

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')

示例输出:
2019-02-28 19:23:45.776951 Process-1 started
2019-02-28 19:23:46.778840 Process-1 terminated

1
action()中,简单的在else之后加上一个返回语句就可以完美解决问题。此外,在你的timer函数中存在错误,你的参数名称与内置库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()

希望这回答了你的问题!

1
你可以通过使用进程间共享状态,创建一个所有并发进程都可以访问的标志值来实现它(尽管这可能有点低效)。
以下是我的建议:
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')

coder44586: 很高兴听到这个消息...不用谢。使用Threading.Timer可能会比将计时作为单独的进程来处理,减少一些开销。 - martineau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接