【发布时间】:2017-01-23 16:41:13
【问题描述】:
我有一个长期运行的计算模型,我希望使用STDIN 和STDOUT 控制、提供数据并从中读取数据。在这个外部代码中,有一个控制反馈循环需要每隔 100 毫秒左右从STDIN 获取新数据。
因此,subprocess.communicate() 不合适,因为它等待进程完成。该流程的预计运行时间约为几周。
下面的代码不起作用,因为控制挂在stdout.read() 上并且永远不会回来。
讨论 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()
【问题讨论】:
-
communicate()本身使用线程。select也是一个选项。与非阻塞 IO 一样。 -
@dhke 是的,但是在进程完成之前,communicate() 不会返回;我想在其单次执行期间多次查询它。
-
因此我的建议:看看沟通是如何做到的并适应您的需求。
communicate()显式等待读取线程。放下它,你就有了持续的轮询。
标签: python python-3.x subprocess stdin