如何根据特定条件终止以 subprocess.Popen() 开头的脚本

How to terminate the script started with subprocess.Popen() based on specific condition

我正在从名为 main.py 的主脚本启动一个名为 test.py 的 Python 脚本。 在 test.py 中,我正在跟踪一些机器学习指标。当这些指标达到某个阈值时,我想终止启动 test.py 的子流程。

如果我通过以下方式启动此脚本,是否有可能在 Python 中实现此目的:
proc = subprocess.Popen("python test.py", shell=True)

我在文档中没有找到任何可以让我自己触发此事件的内容。

已更新 执行此操作的最简单方法是将终止条件作为参数传递给 test.py.

否则,您可以使用 stdoutstdin 的打印和读取。如果您想保留输出并仍然使用 Popen,请参见下文。例如,考虑一个简单的 test.py 计算(以非常低效的方式)一些素数:

test.py

import time

primes = [2, 3]

if __name__ == "__main__":
    for p in primes:
        print(p, flush=True)

    i = 5
    while True:
        for p in primes:
            if i % p == 0:
                break
        if i % p:
            primes.append(i)
            print(i, flush=True)
        i += 2
        time.sleep(.005)

您可以阅读输出并选择在达到所需输出时终止进程。例如,我想获得最大为 1000.

的素数
import subprocess

proc = subprocess.Popen("python test.py",
                        stdout=subprocess.PIPE, stdin=subprocess.PIPE,
                        bufsize=1, universal_newlines=True,
                        shell=True, text=True)
must_stop = False
primes = []
while proc.poll() is None:
    line = proc.stdout.readline()
    if line:
        new_prime = int(line)
        primes.append(new_prime)
        if  new_prime > 1000:
            print("Threshold achieved", line)
            proc.terminate()
        else:
            print("new prime:", new_prime)
print(primes)

请注意,由于处理和通信存在延迟,您可能会比预期多获得一两个素数。如果你想避免这种情况,你需要双向通信并且 test.py 会更复杂。如果你想在屏幕上看到 test.py 的输出,你可以打印它然后以某种方式解析它并检查是否满足条件。其他选项包括使用 os.mkfifo(仅限 Linux,不是很困难),它提供了两个进程之间的简单通信路径:

os.mkinfo版本

test.py

import time
import sys

primes = [2, 3]

if __name__ == "__main__":
    outfile = sys.stdout
    if len(sys.argv) > 1:
        try:
            outfile = open(sys.argv[1], "w")
        except:
            print("Could not open file")
    for p in primes:
        print(p, file=outfile, flush=True)
    i = 5
    while True:
        for p in primes:
            if i % p == 0:
                break
        if i % p:
            primes.append(i)
            print("This will be printed to screen:", i, flush=True)
            print(i, file=outfile, flush=True) # this will go to the main process
        i += 2
        time.sleep(.005)

主文件

import subprocess
import os
import tempfile


tmpdir = tempfile.mkdtemp()
filename = os.path.join(tmpdir, 'fifo')  # Temporary filename
os.mkfifo(filename)  # Create FIFO
proc = subprocess.Popen(["python3", "test.py", filename], shell=False)
with open(filename, 'rt', 1) as fifo:
    primes = []
    while proc.poll() is None:
        line = fifo.readline()
        if line:
            new_prime = int(line)
            primes.append(new_prime)
            if new_prime > 1000:
                print("Threshold achieved", line)
                proc.terminate()
            else:
                print("new prime:", new_prime)
    print(primes)

    pass

os.remove(filename)
os.rmdir(tmpdir)