[python] multiprocessingにおける共有変数の使い方

前回の投稿でpythonにおけるmultiprocessingの基本的な使い方をまとめました. multiprocessingでは複数のプロセスで同時に処理するので基本的に同一変数のメモリの共有は行いません。しかし、実際に使用する時は同一の処理を複数プロセスで行い一つの変数に格納したいことが多いと思います. このような場合はプロセス間で共有の変数を定義することで解決することができます.今回はmultiprocessingにおける共有変数の使い方についてまとめていきます.

共有変数を定義する方法

共有変数を定義する時はValueクラスかArrayクラスを用います. 単純にスカラー値を共有したい時はValueクラスを, 配列を共有したい時はArrayクラスを用いて変数を定義します.また定義した共有変数をPoolクラスのinitializerに引き渡すことでプロセス開始時に変数の共有を行います. 今回は配列を用意して配列の値をインデックスごとにマイナスにする処理を並列処理させました.

ValueクラスやArraykクラスで指定したdは型のタイプで今回はdouble型です。他にもf(float)やi(int)が指定可能です。function内でshared_count.acquire()とありますがこれは変数のアクセスをロックするメソッドで, プロセス間で同一の変数の書き換えを行う場合は処理を始める前にロックしておかないと処理中に変数の値が他のプロセスによって書き換えられてしまうので気をつけてください.

実行結果としては11805-11808の四つのサブプロセスで正しく実行できていることが分かります.

まとめ

今回はpythonのmultiprocessingにおいて共有変数を定義し複数プロセス間で同一の変数にアクセスする方法をまとめました. 複雑な処理になってくるとロックする位置などを間違えると処理結果などが変わってきてしまうため少し面倒ですが使いこなせばかなり便利だと思います. まだまだ使い方の理解が不十分なので分かったことがあったらまとめていきたいと思います.

[python] multiprocessingの基本的な使い方

pythonで処理を早く終わらせたい場面などがあると思います. 基本的にpythonのプログラムを実行すると1つのプロセスが立ち上がって処理をします. この処理を高速化するために複数のプロセスを立ち上げて並列処理することで実行時間を削減することができます. 少し難しいように感じますがpythonでは標準ライブラリにmultiprocessingというライブラリがあり, これを使うことで簡単に並列処理することができます. 今回はこのライブラリの簡単な使い方を紹介していきます.

pythonにおけるmultiprocessingの立ち位置

pythonでは処理を高速化する方法が大きく分けて2つあります. 複数のプロセスを立ち上げて並列処理するmultiprocessingを使用する方法と1つのプロセスを立ち上げて複数のスレッドで並列処理するthreadingがあります. threadingは実装するのが難しい上にそれぞれのクラスを正しく使用していないと多少の高速化をしかできないなど扱いづらい印象があります. その上プログラムがスレッドセーフでないと予期せぬ動作をしてしまいます. 一方, multiprocessingは実装が簡単であり高速化も容易にできます. また, スレッドを使用する代わりにサブプロセス(子プロセス)を使用することで,GILの問題を効率的に回避できるようになっているみたいです. このような理由から, 個人的にpythonで高速化するならmultiprocessingをおすすめします.

multiprocessingの使い方

pythonの標準ライブラリであるmultiprocessingを使い並列処理をする方法を説明していきます。multiprocessingでは並列処理したい処理を関数化し、その定義した関数をPoolクラスを用いて並列処理します。

最初にPoolクラスを生成しますが, その際に使用するコア数を指定します. 今回はマシンの最大使用可能コア数を指定しました. 並列処理したい内容を定義したfunction関数をPoolクラスのmapメソッドの引数で渡すことで実行することができます. mapメソッドの第二引数が並列処理する関数の引数となります. function関数内でsleep関数を使用していますが今回は処理が簡単だったので表示順が前後してしまうのでsleepさせました. 終了したらPoolクラスのcloseメソッドでプロセスを閉じます。closeを忘れると並列処理していたメモリが解放されずに残り続けるので気をつけてください.

子プロセス数は4つで, 親プロセスIDの2618に対して子プロセスIDは2621~2624の4つで実行されていることが分かります.

まとめ

今回は基本的なmultiprocessingの使い方を紹介しました. 実際に使うときは並列処理した結果を1つとして扱いたい場合がほとんどだと思います(並列処理した結果を配列に格納するなど). この場合は複数プロセスの間でメモリを共有することで, それぞれのプロセスの結果を共有することができます. 次回は複数プロセスの間でメモリを共有する方法を紹介します.