2016-05-25 11 views
1

すべてのサブフォルダ内の同じパス構造と同じファイルを持つ2つのフォルダを比較したいと思います。フォルダはかなり大きく、サイズは約80GB、ファイル番号は8000です。Python Multiprocessing imap chunksize

2つのトップディレクトリの下にある対応するファイルペアのmd5チェックサム値が同じであることを確認したいと思います。私は、2つのディレクトリの下にあるすべてのファイルを検索し、ファイルサイズに従ってソートし、2つのリストに格納する単純なツリーDFS関数を作成しました。

リストを繰り返してみると、すべての比較を行うのに非常に時間がかかり、CPU使用率も低くなっています。

私はマルチプロセッシングモジュールがこの場合に適していると思います。

from multiprocessing import Pool, cpu_count 
import hashlib 

def calc_md5(item): 
    m = hashlib.md5() 
    with open(item, 'rb') as f: 
     for chunk in iter(lambda: f.read(4096), b""): 
      m.update(chunk) 
    return m.hexdigest() 

def worker(args): 
    a, b = args 
    return calc_md5(a) == calc_md5(b) 

def multi_compare(queue_a, queue_b, thread): 
    pool = Pool(processes = cpu_count() - 1) 
    # Task iterable 
    task = zip(queue_a, queue_b) 
    # Multiprocessing 
    for retval in pool.imap_unordered(worker, task, chunksize = 5): 
     if not retval: 
      print "Bad Detected" 
ここqueue_a

とqueue_bは、ファイルサイズに応じてソートと比較するファイルのパスです:これは、マルチプロセッシングのための私の実装です。私はこのマルチプロセッシング手法の中でより高いCPU使用率とより良い性能を期待していますが、そうでないようです。シンプルなシーケンシャル・イテレーションには約3200秒かかりますが、マルチプロセッシング・メソッドは約4600秒かかります。

なぜこれが当てはまるのですか?これはマルチプロセッシングを使う良い点ですか?私のコードでこの悪いパフォーマンスのボトルネックは何ですか?それを改善する方法はありますか?

: 私は腸の感情に応じてチャンクサイズを設定しました。私はそれをスレッド番号によって分けられたqueue_aまたはqueue_bの長さに変更することができ、queue_a [0 :: thread]またはqueue_b [0 :: thread]要素を含む最初の1/4のようにタスクキューを並べ替えることができます。これは、同じサイズのタスクをすべてのスレッドに送り、すべてのスレッドを常にビジー状態に保ちます。私はこれが別のパフォーマンスを得る良い方法であるかどうかわからないし、私はまだこれについてテストしています。

: 上記の編集でのテストには4000秒かかります。 Chunksize = 5より少し良い。シリアルメソッドよりもさらに悪い。 このマルチプロセッシングプログラムのボトルネックをどうやって判断することができますか?

ありがとうございました!

+0

ファイルはHDDにありますか?遅いシークのため、ほとんどのHDDはマルチスレッドの読み込みに悪いです。 – robyschek

+0

@robyschekはい、私はHDDのPCにいると思います。私はSSDを使ってそれを試してみる。ありがとう! – yc2986

答えて

0

パフォーマンスを制限するのはIOです。 MD5アルゴリズムはCPUにとって非常に簡単な作業です。 次のコードは、MD5のパフォーマンスをGB/s単位で計算します。

import time 
import hashlib 
from multiprocessing import Pool 

def worker(x): 
    data = bytearray(xrange(256)) * 4 * 1024 
    md5 = hashlib.md5() 
    for x in xrange(1024): 
     md5.update(data) 

if __name__ == '__main__': 
    num_workers = 4 
    pool = Pool(num_workers) 
    start = time.time() 
    pool.map(worker, xrange(num_workers)) 
    print num_workers/(time.time() - start), 'Gb/s' 

比較的弱いインテルの現代のモバイルi3はCPU(2個のコア、4つのスレッド) は、毎秒1ギガビットの速度でハッシュすることができます。これを600 Mb/sの SATA3 bandwidthと比較してください。 SSDを使用している場合でも、ディスクインターフェイスはハッシュ速度を制限します。
HDDでは状況がさらに悪化します。 複数のリーダは、リーダスレッドが1つしか使用されない場合よりも、リーディングヘッドをシフトさせて、より多くの遅延を引き起こします。 非常に断片化したファイルを読み込むようなものです。
データセットがそれほど大きくないと、OSのファイルキャッシュが大きく役立ちます。しかし、あなたの場合ではありません。