use*_*440 3 python stdout multiprocessing sys
我传递"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()
Run Code Online (Sandbox Code Playgroud)
上面的代码不起作用,它返回以下错误:"ValueError:关闭文件上的操作".
我尝试运行相同的代码,但直接调用该函数而不是生成一个进程,它工作,它打印到控制台.我也尝试运行相同的代码,但直接在函数内部调用sys.stdout,将其作为一个进程生成它并且它可以工作.问题似乎是将sys.stout作为进程的参数传递.
有人知道为什么吗?
注意:此代码的灵感来自教程PYMOTW - 进程之间的通信.
编辑:我在Windows7上运行Python 2.7.10,32位.
当您将参数传递给a时Process,它们会在父级中被腌制,传输给子级,并在那里进行切换.不幸的是,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>
Run Code Online (Sandbox Code Playgroud)
命名文件也会出现同样的问题; 它并非标准手柄的独特之处.基本上,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(),))
Run Code Online (Sandbox Code Playgroud)
然后在另一边重新打开它os.fdopen.对于fd不是标准手柄部分(0,1和2),因为Windows用制造新的"重生"的方法ProcessES,你需要确保任何这样fd被开辟为的结果import荷兰国际集团的__main__模块时__name__ != "__main__"(视窗模拟fork通过导入__main__模块,将其设置__name__为其他内容).当然,如果它是一个命名文件,而不是标准句柄,你可以只传递名称并重新打开它.例如,为了使这项工作,您将改变:
def worker_with(stream):
stream.write('In the process\n')
Run Code Online (Sandbox Code Playgroud)
至:
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')
Run Code Online (Sandbox Code Playgroud)
注意:如上所述,如果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看看它将如何使用),但它至少允许传递任意文件描述符,而不仅仅是静态打开的文件描述符.
| 归档时间: |
|
| 查看次数: |
1228 次 |
| 最近记录: |