问:从Python中的另一个函数终止一个函数中调用的进程

时间:2019-02-20 14:58:40

标签: python-2.7 function subprocess python-multiprocessing terminate

我写了一个函数fun0,它调用:

  1. 子流程p1
  2. 函数fun1
  3. 和调用另一个进程fun2的函数p2

两个进程p1p2是外部文件。函数fun0的代码为:

def fun0():

    # call the 1. process        
    p1 = subprocess.Popen(["python", "script1.py"])
    try:
        p1.wait()
    except KeyboardInterrupt:
        try:
            p1.terminate()
        except OSError:
            pass
        p1.wait()

    # call the 1. function
    fun1()

    # loop 3 times
    for i in range(1, 3, 1):   

        # call the 2. function
        fun2()

def fun2():

    # call 2. process
    p2 = subprocess.Popen(["python", "script2.py"])
    try:
        p2.wait()
    except KeyboardInterrupt:
        try:
            p2.terminate()
        except OSError:
            pass
        p2.wait()

script_2.py使用线程来同时运行两个函数。代码如下:

import threading

def Ref():
    read ref. value
    return ref. value

def Read():
    while read_interval <= some_time:
        read value
        yield value

def Add():
    while delta > error:
        while delta > limit :
            while True:
                value = next(Read())
                delta = change delta
                check conditions
        while True:
            value = next(Read())
            delta = change delta
            check conditions
    return result

if __name__ == '__main__':

    t0 = threading.Thread(target = Ref)
    t0.start()
    t0.join()

    readTime = datetime.now()

    t1 = threading.Thread(target = Read)
    t2 = threading.Thread(target = Add)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

我想从外部(即从另一个函数)停止执行函数fun0()。当停止发生时,我还希望函数fun1fun2并处理p1p2以停止并可能从中检索数据。我不知道这是一种优雅,干净和Pythonic的方式。我正在考虑:

  1. 线程,
  2. 多重处理
  3. 使用其他功能
  4. 使用信号吗?

我已经阅读了此post 28906558中有关使用multiprocessing停止该功能的方法,但我想听听更多意见,谢谢。

4 个答案:

答案 0 :(得分:0)

出于这个问题的目的,我对函数fun1以及子流程p1p2使用了简单的倒计时。然后,我开始尝试将该功能用作流程解决方案。主程序的代码是:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-

#An example of how to terminate the execution of a function
#which calls a process using an external trigger.

import time
import subprocess
from multiprocessing import Process, Queue

def fun0():

    # start process1        
    p1 = subprocess.Popen(["python", "eg_script1_countdown1.py"])
    p1_PID = p1.pid
    print "p1_PID:", p1_PID
    try:
        p1.wait()
    except KeyboardInterrupt:
        try:
            p1.terminate()
        except OSError:
            pass
        p1.wait()

    # call function1
    fun1()

    # loop 3 times
    for i in range(1, 3, 1):
        # call fun2
        print "call function 2, loop n.", i
        fun2()

def fun1():
    for i in range(5,0,-1):
        print "fun1 > take five in", i
        time.sleep(1)

def fun2():
    # start process2
    p2 = subprocess.Popen(["python", "eg_script2_countdown2.py"])
    p2_PID = p2.pid
    print "p2_PID:", p2_PID
    try:
        p2.wait()
    except KeyboardInterrupt:
        try:
            p2.terminate()
        except OSError:
            pass
        p2.wait()

if __name__ == '__main__':
    pMain = Process(target=fun0)
    pMain_PID = pMain.pid
    print "pMain_PID:", pMain_PID
    pMain.start()
    time.sleep(20)
    pMain.terminate()

第一个被调用文件的代码为:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-
#eg_script1_countdown.py

import time

for i in range(10,0,-1):
    print "script1.py > have a beer in", i
    time.sleep(1)

以及第二个文件:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-
#eg_script2_countdown.py

import time

for i in range(10,0,-1):
    print "script2.py > give love in", i
    time.sleep(1)

我正在更改time.sleep(20)中的行__name__ == '__main__',以查看内部终端pMain.terminate()如何影响结果。我发现:

  1. 在子进程p1运行时被触发时,它不会终止它,
  2. fun1()运行时被触发时,它会终止功能,
  3. 在子进程p2正在运行时被触发时,它不会终止该过程,但会在下一个循环中终止fun2()

如何在运行时终止子进程p1p2

答案 1 :(得分:0)

我确实按照建议in this threadpMain.daemon = True之前使用pMain.start()修改了主程序的代码,但是进程p1仍然在后台运行,甚至退出了​​。

import os
import time
import signal
import subprocess
from subprocess import Popen, PIPE
import multiprocessing
from datetime import datetime

def fun0():

    p1 = subprocess.Popen(["python", "eg_script1_countdown1.py"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    #p1 = subprocess.Popen(["python", "eg_script1_countdown1.py"])
    global p1_pid
    p1_pid = p1.pid
    print "p1_pid:", p1_pid

    try:
        p1.wait()
    except KeyboardInterrupt:
       try:
            p1.terminate()
       except OSError:
            pass
       p1.wait()

    # call fun1
    fun1()

    # loop 3 times
    for i in range(3):
        # call fun2
        print "call fun2, loop n.", i
        with open('/home/parovelb/Desktop/Python2.7/log.txt', 'a') as log:
                log.write(str(datetime.now()) + '  for loop n. ' + str(i) + "\n")
        fun2()

def fun1():
    for i in range(5,0,-1):
        print "fun1 > take five in", i
        with open('/home/parovelb/Desktop/Python2.7/log.txt', 'a') as log:
                log.write(str(datetime.now()) + '  fun1 ' + str(i) + "\n")
        time.sleep(1)

def fun2():

    # start process2
    p2 = subprocess.Popen(["python", "eg_script2_countdown2.py"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    #p2 = subprocess.Popen(["python", "eg_script2_countdown2.py"])
    global p2_pid
    p2_pid = p2.pid

    try:
        p2.wait()
    except KeyboardInterrupt:
        try:
            p2.terminate()
        except OSError:
            pass
        p2.wait()


if __name__ == '__main__':

    # original code
    pMain = multiprocessing.Process(target=fun0)
    pMain.daemon = True
    pMain.start()
    time.sleep(10)    
    pMain.terminate()
    exit()

答案 2 :(得分:0)

在帖子delegate-sigint-signal...delegate-signal-handling...中提出建议的解决方案之后,我修改了主程序的代码:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-

"""
This is an example of a simple terminaton of a subprocess with a ctrl+c. 
"""

import time
import signal
import subprocess


def signal_handler(signal, frame):
   print "outer signal handler"
   exit(2)


def fun1():
   for i in range(5,0,-1):
        print "fun1 > take five in", i
        time.sleep(1)


def execute():

    # call the process first
    proc = subprocess.Popen("python eg_test.py",shell=True)
    try:
        proc.wait()
    except KeyboardInterrupt:
        try:
            proc.terminate()
        except OSError:
            pass

    # call the function second
    fun1()


def main():

    signal.signal(signal.SIGINT, signal_handler)

    execute()
    time.sleep(5)
    proc.send_signal(signal.SIGINT)


main()

我还只是为了测试运行而修改了一个外部脚本:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-

"""
This is an example of a simple for loop countdown run a subprocess and
terminated with ctrl+c. 
"""

import time
import signal
from datetime import datetime


def signal_handler(signal, frame):
    print "exiting: inner function"
    exit(2)



def main():
    #define the signal handler
    signal.signal(signal.SIGINT, signal_handler)

    # simple for loop countdown
    for i in range(20,0,-1):
        print "test.py > countdown", i
        time.sleep(1)


main()

在过程中按ctrl + c时(正在运行外部脚本),它将终止它,然后继续执行fun1()。问题仍然存在:如何从另一个函数终止execute()函数?

答案 3 :(得分:0)

经过反复试验后,我得到了代码。我感觉还有很多改进的空间。主要脚本的代码:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-

"""
This is an example of a simple terminaton of a subprocess with a ctrl+c. 
"""

import os
import time
import signal
import subprocess
import multiprocessing
from datetime import datetime


p1_pid = 0
proc_pid = 0


def signal_handler(signal, frame):
    print " main signal handler "
    # write to log
    with open('.../Python2.7/log.txt', 'a') as log:
            log.write(str(datetime.now()) + ' exiting: main function ' + "\n")
    exit(2)


def f1():
    for i in range(5,0,-1):
        print "f1 > main function", i
        # write to log
        with open('/home/parovelb/Desktop/Python2.7/log.txt', 'a') as log:
            log.write(str(datetime.now()) + ' main function ' + str(i) + "\n")
        time.sleep(1)


def execute():
    # call the function second
    f1()

    # call the process first
    global p1, p1_pid
    p1 = subprocess.Popen(["python", "eg_test.py"], shell=False)
    p1_pid = p1.pid
    print "p1_pid", p1_pid
    try:
        p1.wait()
    except KeyboardInterrupt:
        try:
            p1.terminate()
        except OSError:
           pass


def kill_them_all():
    time.sleep(10)
    print "p1_pid", p1_pid
    os.kill(p1_pid,signal.SIGINT)
    os.kill(proc_pid,signal.SIGINT)


def main():
    # define signal handler
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    global proc, proc_pid    

    proc = multiprocessing.Process(target=execute)
    proc_pid = proc.pid
    print "proc_pid", proc_pid
    proc_end = multiprocessing.Process(target=kill_them_all)

    proc.start()
    proc_end.start()

    proc.join()
    proc_end.join()


main()

外部脚本的代码:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-


import time
import signal
from datetime import datetime


def signal_handler(signal, frame):
    print " external signal handler "
    with open('.../Python2.7/log.txt', 'a') as log:
            log.write(str(datetime.now()) + ' exiting: external function ' + "\n")
    exit(2)


def main():
    #define the signal handler
    signal.signal(signal.SIGINT, signal_handler)

    # simple for loop countdown
    for i in range(20,0,-1):
        print "eg_test.py > external file > main function", i
        with open('.../Python2.7/log.txt', 'a') as log:
            log.write(str(datetime.now()) + ' external function ' + str(i) + "\n")
        time.sleep(1)


main()