繁体   English   中英

无法使用 Python 从 Windows 上的衍生子进程读取标准输出

[英]Unable to read stdout from spawned subprocess on Windows with Python

I am trying to build a GUI frontend for a very simple windows terminal application (binary available here https://github.com/00-matt/randomx-stress/releases/download/200109/randomx-stress-windows-200109.zip ),然后使用 popen 将终端应用程序作为子进程启动,并将 output 输入队列,然后读取队列并将 output 放入 tkinter GUI。 无论我尝试什么,尽管我无法从生成的子进程中从 stdout 或 stderr 获得任何东西。 这是我的代码的精简版:

from tkinter import *
import subprocess
import threading
import queue
import os
from os import system
from re import sub
import sys

os.environ["PYTHONUNBUFFERED"] = "1"

def enqueue_output(p, q):
    while True:
        out = p.stdout.readline()
        if out == '' and p.poll() is not None:
            break
        if out:
            print(out.strip(), flush=True)
            q.put_nowait(out.strip())


class Window(Frame):

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.master = master
        self.started = False
        self.p = None
        self.q = queue.Queue()
        self.threads = 1
        self.init_window()

    def init_window(self):
        self.master.title("RandomX Stress Tester")
        self.pack(fill=BOTH, expand=1)

        self.hashrateLabel = Label(self, text="Hashrate: ")
        self.hashrateLabel.after(2000, self.refresh_hashrate)

        self.startButton = Button(self, text="Start", background="green", command=self.startstop)
        self.quitButton = Button(self, text="Quit", command=self.client_exit)

        self.hashrateLabel.place(x=50, y=220)
        self.startButton.place(x=50, y=270)
        self.quitButton.place(x=220, y=270)

    def startstop(self):
        if not self.started:
            self.p = subprocess.Popen([r"randomx-stress.exe", "-t", str(self.threads)],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
                        shell=True,
                        encoding='utf-8',
                        errors='replace')
            self.t = threading.Thread(target=enqueue_output, args=(self.p, self.q))
            self.t.daemon = True
            self.t.start()
            self.started = True
            self.startButton.config(text="Stop", background="red")
        elif self.started:
            system("taskkill /im randomx-stress.exe /f")
            self.p.kill()
            self.t.join()
            self.started = False
            self.startButton.config(text="Start", background="green")

    def refresh_hashrate(self):
        print("checking hashrate if running")
        if not self.started:
            pass
        elif self.started:
            print("its running")
            try:
                line = self.q.get_nowait()
                print(line)
                if 'H/s' in line:
                    hashrate = line.split(' ')[0]
                    self.hashrateLabel.text = "Hashrate: {0:.2f} h/s".format(hashrate)
            except:
                print("error")
        self.hashrateLabel.after(2000, self.refresh_hashrate)

    def client_exit(self):
        exit()


root = Tk()
root.geometry("400x300")

app = Window(root)
root.mainloop()

我现在的怀疑是终端应用程序正在缓冲 output,我无法在 Windows 上绕过它。 如果有人可以确认这是问题所在,并且如果可能提供解决方法,我将不胜感激!

基于 C 库的程序对 stdout 的处理方式不同,具体取决于它是终端(假设用户需要逐行数据)还是 pipe(块缓冲区以提高效率)。 在类 Unix 系统上,程序可能会被欺骗,以为它是在带有伪 tty 设备的终端上运行的。 在 Windows 上,微软从未实现过等效技术。 子进程将阻塞缓冲区。

您可以通过在写入后刷新标准输出来解决被调用程序中的问题。 这是在 C++ 中使用endl自动完成的。 在你的情况下,这将是:

std::cout << hashes / difference.count() << " H/s" << endl;

暂无
暂无

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

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