multiprocessing.Manager()
と、それを使用して共有オブジェクト、特にワーカー間で共有できるキューを作成する方法を知っています。 この質問 、 この質問 、 この質問 そして 私自身の質問の1つ もあります。
ただし、非常に多くのキューを定義する必要があり、各キューは特定のプロセスのペアをリンクしています。プロセスの各ペアとそのリンクキューが変数key
によって識別されるとします。
データを入れたり取得したりする必要があるときに、辞書を使用してキューにアクセスしたいと思います。私はこれを機能させることができません。私はいくつかのことを試しました。 multiprocessing
がmp
としてインポートされた場合:
マルチプロセッシングモジュール(_for key in all_keys: DICT[key] = mp.Queue
_と呼びます)によってインポートされた構成ファイルで_multi.py
_のようなdictを定義してもエラーは返されませんが、キュー_DICT[key]
_はプロセス間で共有されません。キューの独自のコピーがあるように見えるため、通信は行われません。
プロセスを定義して開始するメインのマルチプロセッシング関数の先頭でDICT
を定義しようとすると、次のようになります。
_DICT = mp.Manager().dict()
for key in all_keys:
DICT[key] = mp.Queue()
_
エラーが発生します
_RuntimeError: Queue objects should only be shared between processes through
inheritance
_
に変更
_DICT = mp.Manager().dict()
for key in all_keys:
DICT[key] = mp.Manager().Queue()
_
すべてを悪化させるだけです。 main関数内ではなく、_multi.py
_の先頭で同様の定義を試行すると、同様のエラーが返されます。
コード内で各キューに明示的に名前を付けることなく、プロセス間で多くのキューを共有する方法が必要です。何か案は?
編集
プログラムの基本的なスキーマは次のとおりです。
1-いくつかの変数を定義する最初のモジュールをロードし、multi
をインポートし、multi.main()
を起動し、モジュールロードとコード実行のカスケードを開始する別のモジュールをロードします。その間...
2- _multi.main
_は次のようになります。
_def main():
manager = mp.Manager()
pool = mp.Pool()
DICT2 = manager.dict()
for key in all_keys:
DICT2[key] = manager.Queue()
proc_1 = pool.apply_async(targ1,(DICT1[key],) ) #DICT1 is defined in the config file
proc_2 = pool.apply_async(targ2,(DICT2[key], otherargs,)
_
pool
とmanager
を使用するのではなく、次のプロセスも起動していました。
_mp.Process(target=targ1, args=(DICT[key],))
_
3-関数_targ1
_は、メインプロセスから(key
でソートされた)入力データを取得します。結果を_DICT[key]
_に渡して、_targ2
_がその作業を実行できるようにすることを目的としています。これは機能していない部分です。 _targ1
_ s、_targ2
_ sなどは任意の数であるため、キューの数は任意です。
4-これらのプロセスのいくつかの結果は、さまざまな配列の束に送信されます/ pandas key
によってインデックスが付けられ、アクセスできるようにしたいデータフレーム任意のプロセスから、別のモジュールで起動されたプロセスも含まれます。この部分はまだ記述しておらず、別の質問になる可能性があります(上記の3の答えでも4がうまく解決される可能性があるため、ここで説明します)。
multiprocessing.Queue()
を引数として渡して共有しようとしたときに、問題が発生したようです。代わりに 管理キュー を作成することでこれを回避できます:
import multiprocessing
manager = multiprocessing.Manager()
passable_queue = manager.Queue()
マネージャーを使用して作成する場合、キュー自体ではなく、プロキシを格納してキューに渡すため、ワーカーに渡すオブジェクトが処理する場合でもがコピーされた場合でも、同じ基になるデータ構造であるキューを指します。これは(概念的には)C/C++のポインターと非常によく似ています。この方法でキューを作成すると、ワーカープロセスを起動したときにキューを渡すことができます。
これでキューを渡すことができるので、辞書を管理する必要がなくなります。すべてのマッピングを格納する通常の辞書をメインに保持し、ワーカープロセスに必要なキューのみを提供するため、マッピングにアクセスする必要はありません。
この例をここに書きました。ワーカー間でオブジェクトを渡しているように見えるので、ここで行います。処理の2つの段階があり、データがmain
の制御で開始および終了するとします。パイプラインのようにワーカーを接続するキューを作成する方法を見てください。ただし、ワーカーに必要なキューのみを与えることで、マッピングについて知る必要はありません。
import multiprocessing as mp
def stage1(q_in, q_out):
q_out.put(q_in.get()+"Stage 1 did some work.\n")
return
def stage2(q_in, q_out):
q_out.put(q_in.get()+"Stage 2 did some work.\n")
return
def main():
pool = mp.Pool()
manager = mp.Manager()
# create managed queues
q_main_to_s1 = manager.Queue()
q_s1_to_s2 = manager.Queue()
q_s2_to_main = manager.Queue()
# launch workers, passing them the queues they need
results_s1 = pool.apply_async(stage1, (q_main_to_s1, q_s1_to_s2))
results_s2 = pool.apply_async(stage2, (q_s1_to_s2, q_s2_to_main))
# Send a message into the pipeline
q_main_to_s1.put("Main started the job.\n")
# Wait for work to complete
print(q_s2_to_main.get()+"Main finished the job.")
pool.close()
pool.join()
return
if __name__ == "__main__":
main()
コードは次の出力を生成します。
メインは仕事を始めました。
ステージ1はいくつかの作業を行いました。
ステージ2はいくつかの作業を行いました。
メインは仕事を終えました。
プログラムがどのように機能するのかまだよくわからないため、キューまたはAsyncResults
オブジェクトを辞書に格納する例は含めませんでした。しかし、キューを自由に渡すことができるようになったので、必要に応じてキュー/プロセスのマッピングを格納する辞書を作成できます。
実際、実際に複数のワーカー間にパイプラインを構築する場合は、main
の「ワーカー間」キューへの参照を保持する必要さえありません。キューを作成してワーカーに渡し、main
が使用するキューへの参照のみを保持します。本当に「任意の数」のキューがある場合は、古いキューをできるだけ早くガベージコレクションできるようにすることを強くお勧めします。