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

问题描述 投票:0回答:4

我写了一个函数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的功能应该是这样做的方式,但我想听到更多的意见,谢谢。

python-2.7 function subprocess python-multiprocessing terminate
4个回答
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


0
投票

我在pMain.daemon = True之前使用pMain.start()修改了主程序的代码,如同建议的in this thread但是进程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()

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()函数?


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()
© www.soinside.com 2019 - 2024. All rights reserved.