我试图使用multiprocessing
包来并发读取文件并在某些数据转换后覆盖(部分)文件。我知道这似乎有点抽象,但我有一个使用这种并发性扭结来加速我自己的blocksync
fork。Python多处理和文件搜索
下面你可以找到我的代码snipplet:
#!/usr/bin/python2
import multiprocessing
import sys
import time
blocksize=1024
def do_open(f, mode):
f = open(f, mode)
f.seek(0, 2)
size = f.tell()
f.seek(0)
return f, size
def pipe_getblocks(f, pipe, side):
print "Child file object ID: "+str(id(f))
while True:
print "getblocks_seek_prev: "+str(f.tell())
block = f.read(blocksize)
if not block:
break
print "getblocks_seek_next: "+str(f.tell())
pipe.send(block)
def pipe_server(dev):
f, size = do_open(dev, 'r+')
parent,child = multiprocessing.Pipe(False)
reader = multiprocessing.Process(target=pipe_getblocks, args=(f,child,"R"))
reader.daemon = True
reader.start()
child.close()
i = 0
print "Parent file object ID:"+str(id(f))
while True:
try:
block = parent.recv()
except:
break
else:
print str(i)+":pseek: "+str(f.tell()/1024/1024)
f.seek(0,0) # This seek should not be see in the child subprocess...
i = i+1
pipe_server("/root/random.img")
基本上,父进程应该等待孩子来填充管,然后从中读出。请注意0这一行:我把它放在这里来验证父母和孩子各自都有自己的想法,在哪里寻找文件。换句话说,完全是两个不同的过程,我期望父母完成的f.seek
对其孩子没有影响。
然而,似乎这种假设是错误的,因为上面的程序产生以下的输出:
Child file object ID: 140374094691616
getblocks_seek_prev: 0
getblocks_seek_next: 1024
...
getblocks_seek_next: 15360
getblocks_seek_prev: 15360
getblocks_seek_next: 16384
getblocks_seek_prev: 16384
getblocks_seek_next: 17408 <-- past EOF!
getblocks_seek_prev: 17408 <-- past EOF!
getblocks_seek_next: 18432 <-- past EOF!
getblocks_seek_prev: 18432 <-- past EOF!
...
Parent file object ID:140374094691616
0:pseek: 0
1:pseek: 0
2:pseek: 0
3:pseek: 0
4:pseek: 0
5:pseek: 0
6:pseek: 0
7:pseek: 0
8:pseek: 0
9:pseek: 0
10:pseek: 0
...
正如你所看到的,子进程读取过去的EOF或,好了,它所以认为,因为它实际上是从文件的开头读取的。总之,似乎父母的f.seek(0,0)
对子进程有影响,但没有认识到这一点。
我的假设是文件对象存储在共享内存中,所以两个进程都修改相同的数据/对象。这个想法似乎得到了来自父母和子女进程的id(f)
的确认,其报告了相同的数据。但是,在使用multiprocessing
软件包时,我没有发现任何引用说明文件对象保留在共享内存中。
所以,我的问题是:这是预期的行为,还是我失去了明显的东西?
非常明确的解释,和引用手册页+1。我知道基于C的分支很好,因此,如果Python只提供一个简单的包装器,这基本上是**期望的行为。 – shodanshok
双重思考:用fork,当前的偏移量是由孩子继承的,但其文件描述符副本应该有它自己的私有查找位置,所以我不确定在分支'泄漏'后如何完成父级的f.seek()子进程... – shodanshok
不,两个进程都具有相同的文件描述符。 FD是操作系统提供的代表文件和位置的令牌;两个过程最终都有相同的标记,所以最终都会看到底层FD的任何更改。 FD不是一个libc/Python /可以改变的结构,它们只是映射到内核数组中的整数。 –