2017-06-25 16 views
1

python.multiprocessing.sharedctypes.RawArrayを使用して、複数のプロセス間で大量の配列を共有します。そして、私はこの配列が大きければ(> 1または2Gb)、初期化するのが非常に遅くなり、読み書きする時間が非常に遅くなることに気付きました。(読み書き時間は予測できず、時にはかなり速く、スロー)。Pythonの共有メモリへの書き込みは非常に遅い

私は、わずか1つのプロセスを使用する小さなサンプルスクリプトを作成しました。共有配列を初期化し、それを何度も書きます。これらの操作を行う時間を測定します。私は私のPC上で、次の取得このコードを実行すると

import argparse 
import ctypes 
import multiprocessing as mp 
import multiprocessing.sharedctypes as mpsc 
import numpy as np 
import time 

def main(): 
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) 
    parser.add_argument('-c', '--block-count', type=int, default=1, 
         help='Number of blocks to write') 
    parser.add_argument('-w', '--block-width', type=int, default=20000, 
         help='Block width') 
    parser.add_argument('-d', '--block-depth', type=int, default=15000, 
         help='Block depth') 
    args = parser.parse_args() 
    blocks = args.block_count 
    blockwidth = args.block_width 
    depth = args.block_depth 
    start = time.perf_counter() 
    shared_array = mpsc.RawArray(ctypes.c_uint16, blocks*blockwidth*depth) 
    finish = time.perf_counter() 
    print('Init shared array of size {:.2f} Gb: {:.2f} s'.format(blocks*blockwidth*depth*ctypes.sizeof(ctypes.c_uint16)/1024/1024/1024, (finish-start))) 
    numpy_array = np.ctypeslib.as_array(shared_array).reshape(blocks*blockwidth, depth) 
    start = time.perf_counter() 
    for i in range(blocks): 
     begin = time.perf_counter() 
     numpy_array[i*blockwidth:(i+1)*blockwidth, :] = np.ones((blockwidth, depth), dtype=np.uint16) 
     end = time.perf_counter() 
     print('Write = %.2f s' % (end-begin)) 
    finish = time.perf_counter() 
    print('Total time = %.2f s' % (finish-start)) 

if __name__ == '__main__': 
    main() 

は:最後のケースでは

$ python shared-minimal.py -c 1 
Init shared array of size 0.56 Gb: 0.36 s 
Write = 0.13 s 
Total time = 0.13 s 
$ python shared-minimal.py -c 2 
Init shared array of size 1.12 Gb: 0.72 s 
Write = 0.12 s 
Write = 0.13 s 
Total time = 0.25 s 
$ python shared-minimal.py -c 4 
Init shared array of size 2.24 Gb: 5.40 s 
Write = 1.17 s 
Write = 1.17 s 
Write = 1.17 s 
Write = 1.57 s 
Total time = 5.08 s 

、配列のサイズが2 GB以上で、初期化時には、配列のサイズに直線的に依存しませんアレイにセーブサイズスライスを割り当てることは、5倍以上遅くなります。

なぜ起こるのだろうか。私はPython 3.5を使ってUbuntu 16.04でスクリプトを実行しています。私はまた、iotopを使用して、アレイに初期化して書き込みを行うときに、共有配列と同じサイズのディスク書き込みアクティビティがあることに気付きましたが、実際のファイルが作成されているか、それがすべきであると仮定する)。一般的に私のシステムは、大規模な共有アレイの場合でも応答性が低下します。交換はありません。topipcs -muvmstatで確認してください。

+2

システムには2GBの物理メモリがありますか?それは交換のように聞こえる。 – pvg

+0

@pvgには16GBのメモリがあり、64GBのメモリを搭載したコンピュータでもテストしました。結果は必ずしも同じではありませんが、16GBの物理メモリを搭載したコンピュータでは、共有アレイが1.5GB以上になるとスローダウンが著しくなり、64GB共有アレイを搭載したマシンでは約6.5GBになります。また、私は 'top'と' ipcs -mu'を実行しようとしましたが、スワップの使用に変化は見られません。 –

+0

おそらく、 'vmstat'のようなものや、実際のスワップインとアウトを追跡するためのものが必要です。メモリアクセス時間はさまざまな理由で非線形に変化する可能性がありますが、スワップ以外の方法でディスクアクセスや非応答システムについて説明するのは難しいです。 – pvg

答えて

1

より多くの研究の後、私は、Pythonは実際にpymp-で始めている/tmp内のフォルダを作成し、どのファイルがファイルビューアを使用してそれらに表示されておりませんけれども、それは/tmp/は、共有メモリのためのpythonで使用されexatlyのように見えることを発見しました。ファイルキャッシュがフラッシュされると、パフォーマンスが低下しているように見えます。

エンドでの作業溶液をマウントした/tmptmpfsとして:

sudo mount -t tmpfs tmpfs /tmp 

そして、docker runコマンドに--tmpfs /tmp引数を提供することで、最新のドッキングウィンドウを使用している場合。

これを実行すると、読み取り/書き込み操作はRAMで実行され、パフォーマンスは高速で安定します。

まだ/tmpが共有メモリに使用されているのはなぜですか?/dev/shmはすでにtmpfsとしてモンタージュされておらず、共有メモリに使用されているはずです。

関連する問題