2017-02-09 16 views
2

私は数百ギガバイトのデータをバイナリファイルに保存しています。私は無作為にいくつかの連続したレコードを何度も読んで、データのランダムサンプルを取っていきたいと思っています。Pythonの並列バッチでファイルを読む

データは多くのファイルに保存されています。メインファイルは特定の順序でデータを格納しないため、それぞれにソートされたインデックスファイルがあります。私の現在のコードは、多くのファイルがあることを除いて、このようなものです:

index = open("foo.index", 'rb') 
data = open("foo", 'rb') 
index_offset_format = 'Q' 
index_offset_size = struct.calcsize(index_offset_format) 
record_set = [] 
for _ in range(n_batches): 
    # Read `batch_size` offsets from the index - these are consecutive, 
    # so they can be read in one operation 
    index_offset_start = random.randint(0, N_RECORDS - batch_size) 
    index.seek(index_offset_start) 
    data_offsets = struct.iter_unpack(
     index_offset_format, 
     index.read(index_offset_size * batch_size)) 

    # Read actual records from data file. These are not consecutive 
    records = [] 
    for offset in data_offsets: 
     data.seek(offset) 
     records.append(data.read(RECORD_SIZE)) 
    record_set.append(records) 

他のものはレコードで行われます。プロファイリングから、私はそのプログラムが大量のIOバインドされており、ほとんどの時間がindex.readdata.readに費やされていることがわかります。これは、readがブロックされているためです。インタプリタは、OSがディスクのデータを次のランダムなチャンクを要求する前にディスクから読み取るのを待っているため、ディスクアクセスパターンを最適化する機会はありません。だから:私は命令のバッチを渡すことができるいくつかのファイルAPIはありますか?何かのように:

def read_many(file, offsets, lengths): 
    ''' 
    @param file: the file to read from 
    @param offsets: the offsets to seek to 
    @param lengths: the lengths of data to read 
    @return an iterable over the file contents at the requested offsets 
    ''' 

また、複数のファイルオブジェクトを開き、マルチスレッドを使用して複数の読み取りを要求すれば十分でしょうか?または、GILはそれが有用であるのを防ぐでしょうか?

+1

関連性:https://stackoverflow.com/questions/29270818/why-is-a-python-i-o-bound-task-not-blocked-by-the-gil – ekhumoro

+0

ファイルの最小サイズ、最大サイズ、平均サイズはどれくらいですか? – Apalala

答えて

3

プロセスはIOバインドであるため、読み取りの境界はオペレーティングシステムのディスク操作スケジューラとディスクのキャッシュによって設定されます。

実際、コアごと並列化はmultiprocessing.Pool.imap_unordered()で簡単に持っていたことができますいくつかのファイルを持って

def pmap(fun, tasks): 
    from multiprocessing import Pool 
    with Pool() as pool: 
     yield from pool.imap_unordered(fun, tasks) 

for record_set in pmap(process_one_file, filenames): 
    print(record_set) 

を同時に開いて、そしておそらくread()は、各コアで実行されて、図にディスクスケジューラを許可する必要がありますファイル名のリストによって課せられた連続的なスケジュールよりも良いスケジュールを出す。

imap_unordered()の美しさは、他のタスクより早く終了したタスク(異なる実行では順序が異なる可能性がある)から後処理を切り離すということです。

コメントに記載されているとおり、GILは、Pythonコードの実行中にのみ関係します。これは、I/Oでプログラムをブロックする場合には当てはまりません。

関連する問題