当前位置:  开发笔记 > 编程语言 > 正文

将sys.stdout作为参数传递给进程

如何解决《将sys.stdout作为参数传递给进程》经验,为你挑选了1个好方法。

我传递"sys.stdout"作为进程的参数,然后进程在执行其内容时写入"sys.stdout".

import multiprocessing
import sys
def worker_with(stream):
    stream.write('In the process\n')

if __name__ == '__main__':
    sys.stdout.write('In the main\n')
    lock = multiprocessing.Lock()

    w = multiprocessing.Process(target=worker_with, args=(sys.stdout,))

    w.start()
    w.join()

上面的代码不起作用,它返回以下错误:"ValueError:关闭文件上的操作".

我尝试运行相同的代码,但直接调用该函数而不是生成一个进程,它工作,它打印到控制台.我也尝试运行相同的代码,但直接在函数内部调用sys.stdout,将其作为一个进程生成它并且它可以工作.问题似乎是将sys.stout作为进程的参数传递.

有人知道为什么吗?

注意:此代码的灵感来自教程PYMOTW - 进程之间的通信.

编辑:我在Windows7上运行Python 2.7.10,32位.



1> ShadowRanger..:

当您将参数传递给a时Process,它们会在父级中被腌制,传输给子级,并在那里进行切换.不幸的是,pickle对于文件对象,它看起来像是默默地行为不端; 使用协议0,它会出错,但是使用协议2(最高的Python 2协议,以及用于协议的协议multiprocessing),它会静默生成一个垃圾文件对象:

>>> import pickle, sys
>>> pickle.loads(pickle.dumps(sys.stdout, pickle.HIGHEST_PROTOCOL))
', mode '' at 0xDEADBEEF>

命名文件也会出现同样的问题; 它并非标准手柄的独特之处.基本上,pickle不能往返文件对象; 即使它声称成功,结果也是垃圾.

通常,multiprocessing实际上并不期望处理这样的场景; 通常,Processes是工作任务,I/O是通过主进程执行的(因为如果它们都独立写入相同的文件句柄,则会出现交错写入问题).

至少在Python 3.5中,他们修复了这个错误,因此错误很明显(返回的文件类对象open,TextIOWrapper并且Buffered*在使用任何协议进行pickle时都会出错).

您在Windows上可以做的最好的事情是将已知的文件描述符作为参数发送:

sys.stdout.flush()  # Precaution to minimize output interleaving
w = multiprocessing.Process(target=worker_with, args=(sys.stdout.fileno(),))

然后在另一边重新打开它os.fdopen.对于fd不是标准手柄部分(0,12),因为Windows用制造新的"重生"的方法ProcessES,你需要确保任何这样fd被开辟为的结果import荷兰国际集团的__main__模块时__name__ != "__main__"(视窗模拟fork通过导入__main__模块,将其设置__name__为其他内容).当然,如果它是一个命名文件,而不是标准句柄,你可以只传递名称并重新打开它.例如,为了使这项工作,您将改变:

def worker_with(stream):
    stream.write('In the process\n')

至:

import os

def worker_with(toopen):
    opener = open if isinstance(toopen, basestring) else os.fdopen
    with opener(toopen, 'a') as stream:
        stream.write('In the process\n')

注意:如上所述,如果fd是标准句柄之一,os.fdopen则在with语句退出时将关闭基础文件描述符,这可能不是您想要的.如果您需要文件描述符在with块关闭后继续存在,则在传递文件描述符时,您可能希望os.dup在调用之前使用复制句柄os.fdopen,因此这两个句柄彼此独立.

其他解决方案包括将结果写回主进程multiprocessing.Pipe(因此主进程负责传递数据sys.stdout,可能启动线程以异步执行此工作),或使用更高级别的构造(例如multiprocessing.Pool().*map*)使用返回数据return语句而不是显式文件I/O.

如果你真的绝望,使一般这项工作的所有的文件描述符(和不关心的可移植性),而不仅仅是创建标准的句柄和描述符import__main__,你可以使用无证的Windows效用函数multiprocessing.forking.duplicate是用来明确将文件描述符从一个进程复制到另一个进程; 它将是非常hacky(你需要查看其余的Windows定义,multiprocessing.forking.Popen看看它将如何使用),但它至少允许传递任意文件描述符,而不仅仅是静态打开的文件描述符.

推荐阅读
coco2冰冰
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有