Python runs the code through subprocess, and obtains the window output of the code in real time (such as print output, neural network model training and inference-related real-time output, etc.)

1. Demand

The python main process evokes a python sub-process, which will print information in real time when the sub-process is running, and the main process needs to obtain the real-time information of the sub-process.

Here, two situations need to be distinguished: when there are few sub-process messages, such as a sub-process written by myself, which uses print to print part of the information, there is no need to consider the caching problem at this time; when there are many sub-process messages and the output speed is fast, For example, in the training of the yolov5 model, there is a progress bar display in the output, and the data volume is large and the speed is fast. At this time, the caching problem needs to be considered.

Mainly refer to the blog "How to start a new process in python and get the output of the program in real time." and the blog "The use of python subprocess.Popen"

2. Implementation without caching

This situation is applicable when there are few sub-process messages, such as a sub-process written by myself, which uses print to print part of the information.

2.1. Subprocess test code

This code is the subprocess test code testSub.py, and print is used to output the code.

import time

i = 0
while (i<40):
    print("当前处于第{}秒".format(i))
    time.sleep(1)
    i += 1
2.2. Main process code

The code is the main process code testMain.py, use subprocess.popen to run the subprocess testSub.py, and obtain the real-time printing result of the subprocess.

import subprocess
import threading

class CMDProcess(threading.Thread):
    '''
        执行CMD命令行的 进程
    '''
    def __init__(self, args,callback):
        threading.Thread.__init__(self)
        self.args = args
        self.callback=callback
        
    def run(self):
        self.proc = subprocess.Popen(
            self.args,
            bufsize=0,
            shell = False,
            stdout=subprocess.PIPE
        )
        
        while self.proc.poll() is None:
            line = self.proc.stdout.readline()
            line = line.decode("utf8") 
            if(self.callback):
                self.callback(line)


def getSubInfo(text):
    print("子进程测试代码实时输出内容=>" + text)

def main():

    cmd = [
            'python',
            '-u', # 注意,这里必须带上-u
            'testSub.py'
            ]
    print("子进程测试代码的运行命令:", ' '.join(cmd))
    testProcess = CMDProcess(cmd,getSubInfo )
    testProcess.start()

main()

3. Consider the implementation of caching

This situation is applicable to the sub-process with many messages and fast output speed, such as the training of yolov5 model, there is a progress bar display in the output, the data volume is large and the speed is fast.

Here, you only need to provide the main process code, please pay attention to the relevant comments. The code is the main process code testMain.py, use subprocess.popen to run the subprocess testSub.py, and obtain the real-time printing result of the subprocess.

import subprocess
import threading

class CMDProcess(threading.Thread):
    '''
        执行CMD命令行的 进程
    '''
    def __init__(self, args,callback):
        threading.Thread.__init__(self)
        self.args = args
        self.callback=callback
        self.cwd = './' 
        
    def run(self):
        self.proc = subprocess.Popen(
            self.args,
            bufsize=1, # bufsize=0时,为不缓存;bufsize=1时,按行缓存;bufsize为其他正整数时,为按照近似该正整数的字节数缓存
            shell = False,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT, # 这里可以显示yolov5训练过程中出现的进度条等信息
            text=True, # 缓存内容为文本,避免后续编码显示问题
            cwd=self.cwd # 这个参数意思是,当前子进程结束后,其结果保存地址,比如yolov5训练进程结束后会输出模型、检测图片等,可在cwd中找到
        )
        
        while self.proc.poll() is None:
            line = self.proc.stdout.readline()
            self.proc.stdout.flush() # 刷新缓存,防止缓存过多造成卡死
            #line = line.decode("utf8") 
            if(self.callback):
                self.callback(line)


def getSubInfo(text):
    print("子进程测试代码实时输出内容=>" + text)

def main():

    cmd = [
            'python',
            '-u', # 注意,这里必须带上-u
            'testSub.py'
            ]  
    # 这里可以改成yolov5的训练代码,如下
    """
    cmd = [
            'python',
            '-u', # 注意,这里必须带上-u
            'train.py',
            '--img',
            '640',
            '--batch',
            '4',
            '--epochs',
            '1' #等等,请自行添加参数
            ] 
	"""
    print("子进程测试代码的运行命令:", ' '.join(cmd))
    testProcess = CMDProcess(cmd,getSubInfo )
    testProcess.start()

main()

With qt display, the effect is as follows
insert image description here

Guess you like

Origin blog.csdn.net/qq_30841655/article/details/127884956