应用场景
有一个 TeraFast 模块必须在 Python2.7 下运行。Windows 中 Tensorflow 不支持 Python2.7,故以外部调用的方式运行 TeraFast 模块。
Prototype 代码
先上可以运行的原型代码:
Parent Process: proto_parentprocess.py (running in Python 3)
import logging
import signal
import subprocess
import time
from os import kill
import numpy as np
from PIL import Image
''' Description
This script is used in junciton with proto_subprocess.py.
Parent: proto_parentprocess.py
Sub : proto_subprocess.py
Parent create Sub using subprocess. Sub generates images and sends to PIPE. Parent gets images from PIPE and saves it.
This process is running in loop.
'''
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
logger = logging.getLogger()
def main():
# Some settings
cmd = ['/media/kent/DISK2/virtualenv_gallery/py27_tf1_10/bin/python', './proto_subprocess.py']
final_shape = [151, 100, 3]
sleep_time = 0.5 # in sec
save_dir = './protoParentProcessOutput.jpeg'
# Create the subprocess
talkpipe = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
logger.info('Subprocess PID: {}'.format(talkpipe.pid))
try:
while True:
line = talkpipe.stdout.readline()
line = line.decode('utf-8')
line = line.strip()
if line:
line = line.replace('[', '')
line = line.replace(']', '')
np_output = np.fromstring(line, dtype=np.int, sep=' ')
img = np.reshape(np_output, final_shape)
img = img.astype('uint8')
im = Image.fromarray(img)
im.save(save_dir)
logger.info('Image saved to {}'.format(save_dir))
else:
logger.warning('No data.')
time.sleep(sleep_time) # for stabilization purpose
except KeyboardInterrupt:
logger.warning('Killing child...')
kill(talkpipe.pid, signal.SIGTERM)
finally:
kill(talkpipe.pid, signal.SIGTERM)
logger.warning('Killed.')
if __name__ == '__main__':
main()
Child Process: proto_subprocess.py (running in Python 2)
import sys
import time
import numpy as np
from PIL import Image
''' Description
This script is used in junciton with proto_parentprocess.py.
Parent: proto_parentprocess.py
Sub : proto_subprocess.py
Parent create Sub using subprocess. Sub generates images and sends to PIPE. Parent gets images from PIPE and saves it.
This process is running in loop.
'''
# Generate some image
im = Image.open('/home/kent/Pictures/120611460-1.png')
np_im = np.array(im) # uint8
np_im = np_im.astype(np.int)
'''
Because the patent process read the stdout data a line each time using talkpipe.stdout.readline(),
we need to reshape the date to one line so that the parent process can get the whole data at each time.
Why using stdout.readline() not stdout.read()?
I tested it and found that (probably) stdout.read() cannot read data interactively.
'''
write_out = np.reshape(np_im, [1, -1])
while True:
np.savetxt(sys.stdout, write_out, fmt='%d')
sys.stdout.flush()
time.sleep(0.1) # for stabilization purpose
关于 Subprocess 模块
Why subprocess
:
Python的subprocess子进程和管道进行交互 其实在python中,和shell脚本,其他程序交互的方式有很多,比如:
os.system(cmd),os.system只是执行一个shell命令,不能输入、且无返回
os.open(cmd),可以交互,但是是一次性的,调用都少次都会创建和销毁多少次进程,性能太差
所以,建议用subprocess
(另外,这篇被转载的博客的原博主也有很多 Python 和 C++ 交互的例子)
How to use:
Python3学习(四十):python中的subprocess.Popen()使用 也是一篇被转载的博客,对
subprocess.Popen()
的参数和方法介绍了一下。Python多进程(1)——subprocess与Popen() 和上一篇差不多,条理也很清晰。
关于 PIPE 传输数据的方式
思路1: 标准输出
上面我的例子里,用了标准的 sys.stdin
和 sys.stdout
,也就是 PIPE。
用这样的方式,必须注意一下传输的信息的编码类型。
Python 2 里会用 Unicode,直接打印传回的信息会显示类似 u’ … ‘。
Python 3 里会用 bytes,直接打印传回的信息会显示类似 b’ … '。
所以在解码传回的东西的时候,需要注意如何解码方式,我上面给的例子里是 line = line.decode('utf-8')
。
思路2:Pickle 序列化
我们可以考虑用 pickle
先把要传输的东西序列化,然后再用 PIPE 传。接收的时候再用 pickle
反序列化解码就可以了。我没有试过这种方式。不过有人问过这样的问题,说明应该是可以行得通的。
Transmitting a pickled object output between python scripts through a
subprocess.communicate
思路3:PyCommunicator 这是一个民间的 package (developped in Python 2, works only for Windows),是对subprocess
进行了 wrap。达到方便易用的目的。不过很久未更新了。我简单试了一下,Python 2 下可以用,不知道转成 Python 3 可不可以。有兴趣的值得一试。不过我试了一下 Python 3 调用 Python 2 程序,貌似未成功。有可能我的方式不对。
补充
Get realtime output from pythonsubprocess 这个问题和其中链接有更多讨论。