简体   繁体   English

如何在后台运行EXE程序并得到python中的输出

[英]How to run an EXE program in the background and get the outuput in python

I want to run an exe program in the background我想在后台运行一个exe程序
Let's say the program is httpd.exe假设程序是 httpd.exe
I can run it but when I want to get the outupt It get stuck becuase there is no output if It starts successfully.我可以运行它,但是当我想要输出时它会卡住,因为如果它成功启动则没有 output。 But if there is an error It's OK.但是如果有错误 也没关系。

Here is the code I'm using:这是我正在使用的代码:

import asyncio
import os

os.chdir('c:\\apache\\bin')
process, stdout, stderr = asyncio.run(run('httpd.exe'))
print(stdout, stderr)

async def run(cmd):
    proc = await asyncio.create_subprocess_exec(
        cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    stdout, stderr = await proc.communicate()

    return (proc, stdout, stderr)

I tried to make the following code as general as possible:我试图使以下代码尽可能通用:

  1. I make no assumptions as to whether the program being run only writes its output to stdout alone or stderr alone.我不假设正在运行的程序是只将其 output 单独写入 stdout 还是单独写入 stderr。 So I capture both outputs by starting two threads, one for each stream, and then write the output to a common queue that can be read in real time.因此,我通过启动两个线程来捕获两个输出,每个线程一个 stream,然后将 output 写入一个可以实时读取的公共队列。 When end-of-stream in encountered on each stdout and stderr, the threads write a special None record to the queue to indicate end of stream. So the reader of the queue know that after seeing two such "end of stream" indicators that there will be no more lines being written to the queue and that the process has effectively ended.当在每个 stdout 和 stderr 上遇到流结束时,线程将一个特殊的None记录写入队列以指示 stream 结束。因此队列的读者知道在看到两个这样的“流结束”指示符之后将不再有行写入队列,并且该过程已有效结束。
  2. The call to subprocess.Popen can be made with argument shell=True so that this can also built-in shell commands and also to make the specification of the command easier (it can now be a single string rather than a list of strings).可以使用参数shell=True调用subprocess.Popen ,这样它也可以内置 shell 命令,也可以使命令的规范更容易(它现在可以是单个字符串而不是字符串列表)。
  3. The function run_cmd returns the created process and the queue. function run_cmd返回创建的进程和队列。 You just have to now loop reading lines from the queue until two None records are seen.您现在只需要从队列中循环读取行,直到看到两个None记录。 Once that occurs, you can then just wait for the process to complete, which should be immediate.一旦发生这种情况,您就可以等待该过程完成,这应该是立即完成的。
  4. If you know that the process you are starting only writes its output to stdout or stderr (or if you only want to catch one of these outputs), then you can modify the program to start only one thread and specify the subprocess.PIPE value for only one of these outputs and then the loop that is reading lines from the queue should only be looking for one None end-of-stream indicator.如果您知道您正在启动的进程只将其 output 写入 stdout 或 stderr(或者如果您只想捕获这些输出之一),那么您可以修改程序以仅启动一个线程并指定subprocess.PIPE值只有这些输出之一,然后是从队列中读取行的循环应该只寻找一个None流结束指示器。
  5. The threads are daemon threads so that if you wish to terminate based on output from the process that has been read before all the end-of-stream records have been detected, then the threads will automatically be terminated along with the main process.这些线程是守护线程,因此如果您希望根据 output 从在检测到所有流结束记录之前已读取的进程中终止,则线程将与主进程一起自动终止。
  6. run_apache , which runs Apache as a subprocess, is itself a daemon thread.作为子进程运行run_apache的 run_apache 本身就是一个守护线程。 If it detects any output from Apache, it sets an event that has been passed to it.如果它检测到来自 Apache 的任何 output,它会设置一个已传递给它的事件。 The main thread that starts run_apache can periodically test this event, wait on this event, wait for the run_apache thread to end (which will only occur when Apache ends) or can terminate Apache via global variable proc .启动run_apache的主线程可以定期测试这个事件,等待这个事件,等待run_apache线程结束(这只会在 Apache 结束时发生)或者可以通过全局变量proc终止 Apache。
import subprocess
import sys
import threading
import queue


def read_stream(f, q):
    for line in iter(f.readline, ''):
        q.put(line)
    q.put(None) # show no more data from stdout or stderr

def run_cmd(command, run_in_shell=True):
    """
    Run command as a subprocess. If run_in_shell is True, then
    command is a string, else it is a list of strings.
    """
    proc = subprocess.Popen(command, shell=run_in_shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    q = queue.Queue()
    threading.Thread(target=read_stream, args=(proc.stdout, q), daemon=True).start()
    threading.Thread(target=read_stream, args=(proc.stderr, q), daemon=True).start()
    return proc, q

import os

def run_apache(event):
    global proc

    os.chdir('c:\\apache\\bin')
    proc, q = run_cmd(['httpd.exe'], False)
    seen_None_count = 0
    while seen_None_count < 2:
        line = q.get()
        if line is None:
            # end of stream from either stdout or stderr
            seen_None_count += 1
        else:
            event.set() # Seen output line:
            print(line, end='')
    # wait for process to terminate, which should be immediate:
    proc.wait()

# This event will be set if Apache write output:
event = threading.Event()
t = threading.Thread(target=run_apache, args=(event,), daemon=True)
t.start()
# Main thread runs and can test event any time to see if it has done any output:
if event.is_set():
    ...
# The main thread can wait for run_apache thread to normally terminate,
# will occur when Apache terminates:
t.join()
# or the main thread can kill Apache via global variable procL
proc.terminate() # No need to do t.join() since run_apache is a daemon thread

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM