web-dev-qa-db-ja.com

並列ファイル書き込みは効率的ですか?

並列ファイル書き込みが効率的かどうか知りたいのですが。実際、ハードディスクには一度に1つの使用可能な読み取りヘッドがあります。したがって、HDDは一度に1つのタスクを実行できます。しかし、以下のテスト(Python)は私が期待していることと矛盾しています:

コピーするファイルは約1Gbです

スクリプト1(//同じファイルを10回1行ずつ読み書きするタスク):

#!/usr/bin/env python
from multiprocessing import Pool
def read_and_write( copy_filename ):
    with open( "/env/cns/bigtmp1/ERR000916_2.fastq", "r") as fori:
        with open( "/env/cns/bigtmp1/{}.fastq".format( copy_filename) , "w" ) as fout:
            for line in fori:
                fout.write( line + "\n" )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    pool = Pool(processes=4)
    results = pool.map( read_and_write, f_names )

if __name__ == "__main__":
    main()

スクリプト2(同じファイルを10回1行ずつ読み書きするタスク):

#!/usr/bin/env python
def read_and_write( copy_filename ):
    with open( "/env/cns/bigtmp1/ERR000916_2.fastq", "r") as fori:
        with open( "/env/cns/bigtmp1/{}.fastq".format( copy_filename) , "w" ) as fout:
            for line in fori:
                fout.write( line + "\n" )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    for n in f_names:
        result = read_and_write( n )

if __name__ == "__main__":
    main()

スクリプト3(//同じファイルを10回コピーするタスク):

#!/usr/bin/env python
from shutil import copyfile
from multiprocessing import Pool
def read_and_write( copy_filename ):
    copyfile( "/env/cns/bigtmp1/ERR000916_2.fastq", "/env/cns/bigtmp1/{}.fastq".format( copy_filename) )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    pool = Pool(processes=4)
    results = pool.map( read_and_write, f_names )

if __name__ == "__main__":
    main()

スクリプト4(同じファイルを10回コピーするタスク):

#!/usr/bin/env python
from shutil import copyfile
def read_and_write( copy_filename ):
    copyfile( "/env/cns/bigtmp1/ERR000916_2.fastq", "/env/cns/bigtmp1/{}.fastq".format( copy_filename) )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    for n in f_names:
        result = read_and_write( n )

if __name__ == "__main__":
    main()

結果:

$ # // task to read and write line by line 10 times a same file
$ time python read_write_1.py

real    1m46.484s
user    3m40.865s
sys 0m29.455s

$ rm test_jm*
$ # task to read and write line by line 10 times a same file
$ time python read_write_2.py

real    4m16.530s
user    3m41.303s
sys 0m24.032s

$ rm test_jm*
$ # // task to copy 10 times a same file
$ time python read_write_3.py

real    1m35.890s
user    0m10.615s
sys 0m36.361s


$ rm test_jm*
$ # task to copy 10 times a same file
$ time python read_write_4.py

real    1m40.660s
user    0m7.322s
sys 0m25.020s
$ rm test_jm*

これらの基本的な結果は、// ioの読み取りと書き込みがより効率的であることを示しているようです。

光をありがとう

12
bioinfornatics

並列ファイル書き込みが効率的かどうか知りたいのですが。

簡単な答え:物理的に複数のスレッドから同じディスクに同時に書き込むことは、1つのスレッドからそのディスクに書き込むよりも速くなることはありません( normalハードディスクはこちら)。場合によっては、さらに遅くなることもあります。

しかし、いつものように、それは多くの要因に依存します:

  • OSディスクキャッシング:書き込みは通常、OSによってキャッシュに保持され、チャンクでディスクに書き込まれます。したがって、複数のスレッドが問題なく同時にそのキャッシュに書き込むことができ、そうすることで速度の利点があります。特に、データの処理/準備にディスクの書き込み速度よりも時間がかかる場合。

  • 場合によっては、複数のスレッドから物理ディスクに直接書き込む場合でも、OSはこれを最適化し、各ファイルに大きなブロックのみを書き込みます。

  • ただし、最悪のシナリオでは、毎回小さなブロックがディスクに書き込まれる可能性があり、その結果、すべてのファイルスイッチでハードディスクシーク(通常のhddで±10ms!)が必要になります(SSDで同じことを行うと、より直接的なアクセスがあり、シークが必要ないため、非常に悪いです)。

したがって、一般に、複数のスレッドから同時にディスクに書き込む場合は、メモリ内の(一部の)データを準備し、ある種のロックを使用して、またはおそらく専用のロックを使用して、最終的なデータをより大きなブロックでディスクに書き込むことをお勧めします。 writer-thread。書き込み中にファイルが大きくなる場合(つまり、ファイルサイズが事前に設定されていない場合)、データをより大きなブロックに書き込むことで、ディスクの断片化を防ぐこともできます(少なくとも可能な限り)。

一部のシステムではまったく違いがない場合がありますが、他のシステムでは大きな違いが生じ、非常に遅くなる可能性があります(または同じシステムで異なるハードディスクを使用している場合でも)。

単一スレッドと複数スレッドを使用した書き込み速度の違いを適切にテストするには、ファイルの合計サイズを使用可能なメモリよりも大きくする必要があります。または、終了時間を測定する前に、少なくともすべてのバッファをディスクにフラッシュする必要があります。ここでは、OSディスクキャッシュにデータを書き込むのにかかる時間だけを測定することはあまり意味がありません。

理想的には、すべてのデータをディスクに書き込むために測定された合計時間は、物理ハードディスクの書き込み速度と等しくなければなりません。 1つのスレッドを使用したディスクへの書き込みがディスクの書き込み速度よりも遅い場合(つまり、データの処理はデータの書き込みよりも時間がかかります)、明らかに多くのスレッドを使用すると処理速度が向上します。複数のスレッドからの書き込みがディスクの書き込み速度よりも遅くなると、異なるファイル(または同じ大きなファイル内の異なるブロック)を切り替えることにより、ディスクシークで時間が失われます。

大量のディスクシークを実行する際の時間の損失を把握するために、いくつかの数値を見てみましょう。

たとえば、書き込み速度が50MB /秒のHDDがあります。

  • 50MBの連続したブロックを1つ書き込むには、1秒かかります(理想的な状況では)。

  • file-switchを使用して、1MBのブロックで同じことを実行し、その間にディスクシークを実行すると、1MBの書き込みに20ms + 10msのシーク時間が得られます。 50MBの書き込みには1.5秒かかります。これは時間の50%の増加であり、その間にクイックシークを実行するだけです(ディスクからの読み取りにも同じことが当てはまります-違いはより速い読み取り速度を考慮すると、より大きくなります)。

実際には、システムによっては、その中間になります。

OSがすべてをうまく処理することを期待できますが(または [〜#〜] iocp [〜#〜] などを使用して)、常にそうであるとは限りません。

19
Danny_ds