经过系统标准输出作为过程的参数

2024-03-29 09:21:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我路过”系统标准输出作为进程的参数,然后进程写入系统标准输出“当它做它的事情。在

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:operation on closed file”。在

我试着运行相同的代码,但是直接调用函数而不是生成一个进程,它会输出到控制台。 我也尝试运行相同的代码,但直接调用系统标准输出在函数内部,将它作为一个进程生成,它就可以工作了。 问题似乎已经过去了系统结实作为过程的参数。在

有人知道为什么吗?在

注意:这段代码受教程PYMOTW-进程间通信的启发。在

编辑:我在Windows7上运行32位的Python2.7.10。在


Tags: the代码inimportstream参数标准进程
1条回答
网友
1楼 · 发布于 2024-03-29 09:21:23

当您将参数传递给Process时,它们在父对象中被pickle,传递给子对象,并在那里取消拾取。不幸的是,对于文件对象,pickle的往返过程似乎会悄无声息地出错;对于协议0,它会出错,但是对于协议2(最高的Python 2协议,也是用于multiprocessing)的协议),它会无声地生成一个垃圾文件对象:

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

命名文件也会出现同样的问题;它不是标准句柄所特有的。基本上,pickle不能往返文件对象;即使它声称成功,结果也是垃圾。在

一般来说,multiprocessing并不真的需要处理这样的场景;通常,Processes是工作任务,I/O是通过主进程执行的(因为如果它们都独立地写入同一个文件句柄,则会出现交叉写入的问题)。在

至少在Python3.5中,他们修复了这个问题,因此错误是即时的和明显的(由openTextIOWrapperBuffered*返回的类似文件的对象在使用任何协议pickle时都会出错)。在

在Windows上,最好的方法是发送已知的文件描述符作为参数:

^{pr2}$

然后在另一侧使用^{}重新打开它。对于fd,由于011,以及{{}}}{}})的标准处理的一部分,由于Windows使用“spawn”的“spawn”方法来产生新的{{>},因此,您需要确保任何这样的{{}是在{{}}{{})是在{{}}{{}{{{}{{{}{{{}}}{{}}{{}}}}}}{{{{{{}模块,将__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.fdopen之前使用{a2}来复制句柄,因此这两个句柄彼此独立。在

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

如果您真的很想让所有的文件描述符都能正常工作(并且不关心可移植性),而不仅仅是在__main__import上创建的标准句柄和描述符,那么您可以使用the undocumented Windows utility function ^{},它用于显式地将文件描述符从一个进程复制到另一个进程;这将是令人难以置信的黑客行为(您需要查看multiprocessing.forking.Popen的其余Windows定义,以了解如何使用它),但它至少允许传递任意文件描述符,而不仅仅是静态打开的描述符。在

相关问题 更多 >