我試圖使用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 /可以改變的結構,它們只是映射到內核數組中的整數。 –