简体   繁体   English

在python中长时间运行的子进程上写入stdin并从stdout读取

[英]write to stdin and read from stdout on long-running child process in python

I have a long-running computational model that i wish to control, feed data to, and read data from using STDIN and STDOUT . 我有一个长期运行的计算模型,我希望使用STDINSTDOUT进行控制,向其输入数据以及从中读取数据。 Inside this external code, there's a control feedback loop that needs new data from STDIN every 100ms or so. 在此外部代码中,有一个控制反馈循环,每100毫秒左右需要一次来自STDIN新数据。

for this reason, subprocess.communicate() is not appropriate, since it waits for the process to finish. 因此, subprocess.communicate()不适合,因为它等待进程完成。 The process' estimated runtime is on the order of several weeks. 该过程的估计运行时间约为数周。

The code below doesn't work because control hangs on stdout.read() and never comes back. 下面的代码不起作用,因为控件挂在stdout.read()并且永远不会回来。

What is the correct way to talk over STDIN and STDOUT ? 通过STDIN和STDOUT进行交谈的正确方法是什么?

import subprocess as sb


class Foo:
    def process_output(self,values: str) -> ():
        """ gets 7 comma separated floats back from ADC.elf and returns them as a tuple of two vectors """
        floats = [float(f) for f in values.split(',') if values and f]
        # if len(floats) == 7:
        mag = (floats[0], floats[1], floats[2])
        quat = (floats[3], floats[4], floats[5], floats[6])
        return (mag, quat)

    def format_input(self,invals: {}) -> bytes:
        """ takes a dict of arrays and stuffs them into a comma-separated bytestring to send to ADC.elf with a trailing newline"""
        concat = lambda s, f: ''.join([f % x for x in s])
        retval = ''
        retval += concat(invals['mag_meas'], '%3.2f,')
        retval += concat(invals['euler_angle'], '%3.2f,')
        retval += concat(invals['sun_meas'], '%3.2f,')
        retval += concat(invals['epoch'], '%02.0f,')
        retval += concat(invals['lla'], '%3.2f,')
        retval += concat([invals['s_flag']], '%1.0f,')
        retval = retval[:-1]
        retval += '\n'
        return retval.encode('utf-8')

    def page(self,input: {}) -> ():
        """ send a bytestring with 19 floats to ADC.elf.  Process the returned 7 floats into a data struture"""
        formatted = self.format_input(input)
        self.pid.stdin.write(formatted)
        response = self.pid.stdout.read()

        return self.process_output(response.decode())

    def __init__(self):
        """ start the long-running process ADC.elf that waits for input and performs some scientific computation"""
        self.pid = sb.Popen(args=['./ADC.elf'], stdin=sb.PIPE, stdout=sb.PIPE, stderr=sb.PIPE)

    def exit(self):
        """ send SIGTERM to ADC.elf"""
        self.pid.terminate()



if __name__ == "__main__":
    # some dummy data
    testData = {'mag_meas': [1, 2, 3],
                'euler_angle': [4, 5, 6],
                'sun_meas': [7, 8, 9],
                'epoch': [0, 1, 2, 3, 4, 5],
                'lla': [6, 7, 8],
                's_flag': 9
                }
    #initialize
    runner = Foo()
    # send and receive once.
    result = runner.page(testData)
    print(result)
    #clean up
    runner.exit()

No idea how to do this with subprocess directly, but pexpect did exactly the right thing: 不知道如何直接使用子流程执行此操作,但是pexpect确实做了正确的事情:

import pexpect, os
from time import sleep

class Foo:
    def process_output(self,values: str) -> ():
        floats = [float(f) for f in values.split(',') if values and f]
        # if len(floats) == 7:
        mag = (floats[0], floats[1], floats[2])
        quat = (floats[3], floats[4], floats[5], floats[6])
        return (mag, quat)

    def format_input(self,invals: {}) -> bytes:
        concat = lambda s, f: ''.join([f % x for x in s])
        retval = ''
        retval += concat(invals['mag_meas'], '%3.2f,')
        retval += concat(invals['euler_angle'], '%3.2f,')
        retval += concat(invals['sun_meas'], '%3.2f,')
        retval += concat(invals['epoch'], '%02.0f,')
        retval += concat(invals['lla'], '%3.2f,')
        retval += concat([invals['s_flag']], '%1.0f,')
        retval = retval[:-1]
        retval += '\n'
        return retval.encode('utf-8')

    def page(self,input: {}) -> ():
        formatted = self.format_input(input)
        self.pid.write(formatted)
        response = self.pid.readline()

        return self.process_output(response.decode())

    def __init__(self):

        self.pid = pexpect.spawn('./ADC.elf')
        self.pid.setecho(False)

    def exit(self):
        self.pid.terminate()



if __name__ == "__main__":
    testData = {'mag_meas': [1, 2, 3],
                'euler_angle': [4, 5, 6],
                'sun_meas': [7, 8, 9],
                'epoch': [0, 1, 2, 3, 4, 5],
                'lla': [6, 7, 8],
                's_flag': 9
                }
    runner = Foo()
    i = 0
    while i < 100:
        result = runner.page(testData)
        print(result)
        i += 1
        sleep(.1)



    runner.exit()

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

相关问题 重复写入stdin并从python中读取进程的stdout - Repeatedly write to stdin and read from stdout of a process from python 如何在 python 中广泛和/或交替地从 stdout 和/或 stderr 读取并写入进程的 stdin? - How to wildly and/or alternatingly read from stdout and/or stderr and write to stdin of a process in python? Python - 如何从长时间运行的子进程中读取? - Python - How to read from long-running subprocess? python asyncio如何读取StdIn并写入StdOut? - python asyncio how to read StdIn and write to StdOut? 长时间运行的Python进程,它接受来自另一个非Python进程的输入 - Long-running Python process that accepts inputs from another non-Python process 清理从 Flask MethodView API 启动的长时间运行的子进程 - Clean up long-running child process launched from Flask MethodView API 如何在python worker中处理长时间运行的请求? - how to process long-running requests in python workers? Python 3、Tkinter 和线程化一个长时间运行的进程,OOP 风格 - Python 3, Tkinter and threading a long-running process, OOP style 如何在进程stdin 仍在运行时写入进程stdin 并从其stdout 中读取? - how can I write to a processes stdin and read from its stdout while it is still running? 从Python进程中的stdin读取? - Read from stdin in Python Process?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM