通过subprocess.communicate在python脚本之间传输pickle对象输出
我有两个python脚本:object_generator.py,它pickle一个给定的对象并打印它。另一个脚本对象_consumer.py通过subprocess.communicate拾取第一个脚本的输出,并尝试使用pickle.loads解除对其的pickle。我很难让这个简单的场景工作。这是我的代码: object_generator.py object_consumer.py通过subprocess.communicate在python脚本之间传输pickle对象输出,python,python-3.x,pickle,Python,Python 3.x,Pickle,我有两个python脚本:object_generator.py,它pickle一个给定的对象并打印它。另一个脚本对象_consumer.py通过subprocess.communicate拾取第一个脚本的输出,并尝试使用pickle.loads解除对其的pickle。我很难让这个简单的场景工作。这是我的代码: object_generator.py object_consumer.py 显然,我需要去掉尾随\r\n,这很容易,但接下来应该做什么?这里有几个问题。首先,在object\u gen
显然,我需要去掉尾随\r\n,这很容易,但接下来应该做什么?这里有几个问题。首先,在
object\u generator.py
中打印一个bytes
对象。在Python3.x中,这将导致调用str(obj)
,这意味着打印b'yourbyteshere'
。您不需要前导的b'
或尾随的'
。要解决这个问题,需要将字节
对象编码为字符串pickle
使用'latin-1'
编码,因此我们可以使用它将字节
对象解码为str
。另一个问题是,默认情况下,编码窗口用于sys.stdout
实际上不支持打印解码的pickle
字符串。因此,我们需要将sys.stdout
*的默认编码更改为'latin-1'
,这样字符串将以正确的编码发送到父进程
import pickle
import base64
import codecs
o = {'first':1,'second':2,'third':3,'ls':[1,2,3]}
d = pickle.dumps(o)
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1')
print(d.decode('latin-1'), end='', flush=True) # end='' will remove that extra \r\n
做出这些改变,它应该可以正常工作
编辑:
另一个选项是从父进程将pythonionecoding
环境变量设置为'latin-1'
:
env = os.environ.copy()
env['PYTHONIOENCODING'] = 'latin-1'
proc = subprocess.Popen(['python3', 'async2.py'] ,stdout=subprocess.PIPE, env=env)
*有关在Python3中更改
sys.stdout
编码的更多信息,请参阅。这里提到的两种方法。我不建议您在主文件和未知外部文件之间使用pickle,因为它要求原始类处于活动状态,而且速度也很慢
我使用了marshall模块,希望这能节省您的时间:您的工作目标是使用给定的
子流程
模块方法.communicate()
,还是实现python进程到进程的通信解决方案,是使用子流程
还是其他方式?我尝试了子流程。检查输出,然后在不起作用时移动到通信,但我没有使用通信的限制。我希望您能提供任何替代方法,并解释其中的错误。最好将进程间通信问题与有效负载表示/编码/序列化/封装/成帧问题分开。对于前者,可能有助于了解快速、可扩展的进程到进程消息传递ZeroMQ(具有许多端口,包括python)的概况,在ZeroMQ中,您可以获得自己控制下的所有功能,从而能够将通信原型适配到分布式并行处理项目的需要中。我看到你收回了你的答案并重新发布了修复。感谢您的耐心和付出的努力。@rusticbit是的,我最初的答案在Linux上运行良好,但在Windows上不起作用。我忘记了Windows上使用的默认编码sys.stdout
的区别。@rusticbit我更新了答案,使用io
模块,而不是codecs
,因为io
模块。我还添加了一种从父脚本解决问题的方法。
import pickle
import base64
import codecs
o = {'first':1,'second':2,'third':3,'ls':[1,2,3]}
d = pickle.dumps(o)
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1')
print(d.decode('latin-1'), end='', flush=True) # end='' will remove that extra \r\n
env = os.environ.copy()
env['PYTHONIOENCODING'] = 'latin-1'
proc = subprocess.Popen(['python3', 'async2.py'] ,stdout=subprocess.PIPE, env=env)