私は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")
基本的には、親プロセスは、それから読んでパイプを埋めるために子供を待つ必要があります。 f.seek(0,0)
行に注意してください。ここでは、親と子それぞれがファイル内でどこを探すべきかという独自の考えを持っていることを確認するためにここに示します。言い換えれば、全く異なる2つのプロセスであることから、私は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
それについて二重に考えてみましょう:フォークでは、現在のオフセットは子によって継承されますが、ファイル記述子のコピーは独自のプライベートシーク位置を持つ必要がありますので、親のf.seek()を 'leaks'子プロセス... – shodanshok
いいえ、両方のプロセスが同じファイル記述子を持っています。 FDは、ファイルと位置を表すOS提供のトークンです。両方のプロセスは同じトークンになります。その結果、両方のプロセスが基礎となるFDの変更を見ることになります。 FDは、libc/Python /何かを変更できる構造体ではなく、カーネル内の配列にマップされる整数だけです。 –