5

シングルスレッドの Python プログラムがあり、それを実行するサーバーの 32 個のプロセッサすべてを利用できるように変更したいと考えています。私が想像しているように、各ワーカー プロセスはキューからジョブを受け取り、その出力をキューに送信します。ただし、作業を完了するには、各ワーカー プロセスが複雑なメモリ内データ構造 (相互にリンクする何ギガバイトもの辞書とオブジェクト) に読み取り専用でアクセスする必要があります。Python では、ワーカー プロセスごとにコピーを作成せずに、このデータ構造を共有する簡単な方法はありますか?

ありがとう。

4

2 に答える 2

15

Python の CPython (または PyPy) 実装を使用している場合、グローバル インタープリター ロック (GIL)により、一度に複数のスレッドが Python オブジェクトで動作することが防止されます。

したがって、このような実装を使用している場合、32 個のプロセッサを活用するには、複数のスレッドではなく複数のプロセスを使用する必要があります。

標準ライブラリのmultiprocessingまたはconcurrent.futuresモジュールを使用して、ワーカー プロセスを生成できます。多くのサードパーティ オプションもあります。Doug Hellman のチュートリアルは、マルチプロセッシング モジュールの優れた入門書です。

データ構造への読み取り専用アクセスのみが必要なため、プロセスを生成するに複雑なデータ構造をグローバル変数に割り当てると、すべてのプロセスがこのグローバル変数にアクセスできるようになります。

プロセスを生成すると、呼び出しモジュールのグローバルが生成されたプロセスにコピーされます。ただし、 copy-on-writeを備えた Linux では、生成されたプロセスでまったく同じデータ構造が使用されるため、追加のメモリは必要ありません。プロセスがデータ構造を変更した場合にのみ、データ構造が新しい場所にコピーされます。

Windows では、存在しないためfork、生成された各プロセスは python を呼び出し、呼び出しモジュールを再インポートするため、各プロセスは巨大なデータ構造の独自の個別のコピー用にメモリを必要とします。Windows でデータ構造を共有するには別の方法があるはずですが、詳細はわかりません。(編集:POSHは共有メモリの問題の解決策かもしれませんが、自分で試したことはありません。)

于 2013-10-14T18:14:26.560 に答える
4

上記のunutbuの回答のデモンストレーションを追加するために、実際にCOW共有メモリであることを示すコードを次に示します(CPython 3.6、Mac OS)

main_shared.py

import multiprocessing
from time import sleep


my_global = None


def test():
    global my_global
    read_only_secs = 3
    while read_only_secs > 0:
        sleep(1)
        print(f'child proc global: {my_global} at {hex(id(my_global))}')
        read_only_secs -= 1
    print('child proc writing to copy-on-write...')
    my_global = 'something else'
    while True:
        sleep(1)
        print(f'child proc global: {my_global} at {hex(id(my_global))}')


def set_func():
    global my_global
    my_global = [{'hi': 1, 'bye': 'foo'}]

if __name__ == "__main__":
    print(f'main proc global: {my_global} at {hex(id(my_global))}')
    set_func()
    print(f'main proc global: {my_global} at {hex(id(my_global))}')
    p1 = multiprocessing.Process(target=test)
    p1.start()

    while True:
        sleep(1)
        print(f'main proc global: {my_global} at {hex(id(my_global))}')

出力

$ python main_shared.py 
main proc global: None at 0x101b509f8
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc writing to copy-on-write...
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: something else at 0x1022ea3b0
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: something else at 0x1022ea3b0
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: something else at 0x1022ea3b0
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
于 2020-02-22T03:34:54.630 に答える