簡體   English   中英

如何在后台運行EXE程序並得到python中的輸出

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

我想在后台運行一個exe程序
假設程序是 httpd.exe
我可以運行它,但是當我想要輸出時它會卡住,因為如果它成功啟動則沒有 output。 但是如果有錯誤 也沒關系。

這是我正在使用的代碼:

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)

我試圖使以下代碼盡可能通用:

  1. 我不假設正在運行的程序是只將其 output 單獨寫入 stdout 還是單獨寫入 stderr。 因此,我通過啟動兩個線程來捕獲兩個輸出,每個線程一個 stream,然后將 output 寫入一個可以實時讀取的公共隊列。 當在每個 stdout 和 stderr 上遇到流結束時,線程將一個特殊的None記錄寫入隊列以指示 stream 結束。因此隊列的讀者知道在看到兩個這樣的“流結束”指示符之后將不再有行寫入隊列,並且該過程已有效結束。
  2. 可以使用參數shell=True調用subprocess.Popen ,這樣它也可以內置 shell 命令,也可以使命令的規范更容易(它現在可以是單個字符串而不是字符串列表)。
  3. function run_cmd返回創建的進程和隊列。 您現在只需要從隊列中循環讀取行,直到看到兩個None記錄。 一旦發生這種情況,您就可以等待該過程完成,這應該是立即完成的。
  4. 如果您知道您正在啟動的進程只將其 output 寫入 stdout 或 stderr(或者如果您只想捕獲這些輸出之一),那么您可以修改程序以僅啟動一個線程並指定subprocess.PIPE值只有這些輸出之一,然后是從隊列中讀取行的循環應該只尋找一個None流結束指示器。
  5. 這些線程是守護線程,因此如果您希望根據 output 從在檢測到所有流結束記錄之前已讀取的進程中終止,則線程將與主進程一起自動終止。
  6. 作為子進程運行run_apache的 run_apache 本身就是一個守護線程。 如果它檢測到來自 Apache 的任何 output,它會設置一個已傳遞給它的事件。 啟動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