在python中长时间运行的子进程上写入stdin并从stdout读取
我有一个长期运行的计算模型,我希望使用在python中长时间运行的子进程上写入stdin并从stdout读取,python,python-3.x,subprocess,stdin,Python,Python 3.x,Subprocess,Stdin,我有一个长期运行的计算模型,我希望使用STDIN和STDOUT控制、向其提供数据以及从中读取数据。在这个外部代码中,有一个控制反馈回路,需要每隔100ms左右从STDIN获取新数据 因此,子流程.communicate()不合适,因为它等待流程完成。进程的估计运行时间大约为几周。 下面的代码不起作用,因为控件挂起stdout.read(),并且永远不会回来 谈论标准输入和标准输出的正确方式是什么 import subprocess as sb class Foo: def proce
STDIN
和STDOUT
控制、向其提供数据以及从中读取数据。在这个外部代码中,有一个控制反馈回路,需要每隔100ms左右从STDIN
获取新数据
因此,子流程.communicate()
不合适,因为它等待流程完成。进程的估计运行时间大约为几周。
下面的代码不起作用,因为控件挂起stdout.read()
,并且永远不会回来
谈论标准输入和标准输出的正确方式是什么
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()
不知道如何直接使用子流程执行此操作,但
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()
导入预期,操作系统
从时间上导入睡眠
Foo类:
def进程_输出(自身,值:str)->():
floats=[float(f)表示值中的f。如果值与f相同,则拆分(',')]
#如果len(浮动)==7:
mag=(浮动[0],浮动[1],浮动[2])
quat=(浮动[3],浮动[4],浮动[5],浮动[6])
返回(mag,quat)
def格式_输入(self,invals:{})->字节:
concat=lambda s,f:''。连接([f%x表示s中的x])
retval=''
retval+=concat(无效['mag_meas'],'%3.2f')
retval+=混凝土(无效['euler_角],'%3.2f')
retval+=concat(无效['sun_meas'],'%3.2f')
retval+=concat(无效['epoch','%02.0f')
retval+=concat(无效['lla'],'%3.2f')
retval+=concat([invals['s_flag']],'%1.0f')
retval=retval[:-1]
retval+='\n'
返回retval.encode('utf-8')
def页面(自身,输入:{})->():
格式化=自。格式化\u输入(输入)
self.pid.write(格式化)
response=self.pid.readline()
返回self.process\u输出(response.decode())
定义初始化(自):
self.pid=peexpect.spawn('./ADC.elf')
self.pid.setecho(False)
def出口(自):
self.pid.terminate()
如果名称=“\uuuuu main\uuuuuuuu”:
testData={'mag_-meas':[1,2,3],
“欧拉角”:[4,5,6],
"sun_meas":[7,8,9],,
“时代”:[0,1,2,3,4,5],
“lla”:[6,7,8],
“s_标志”:9
}
runner=Foo()
i=0
当我<100时:
结果=runner.page(testData)
打印(结果)
i+=1
睡眠(.1)
runner.exit()
本身使用线程。这也是一种选择。与非阻塞IO一样。@dhke这是真的,但是communicate()在进程完成之前不会返回;我想在一次执行过程中多次查询它。因此我的建议是:看看它是如何进行通信的,并适应您的需要<代码>通信()显式等待读卡器线程。放下它,你就有了连续的投票。