やあ、みんな! 今回は、Pythonのマルチプロセッシングについて学びます。
では、さっそく始めましょう。
マルチプロセシングとは?
マルチプロセシングは Python のパッケージで、Python API を利用したプロセスの起動をサポートします。
Python の threading モジュールに似ています。
Python でマルチプロセッシングを理解する
マルチプロセッサとは、コンピュータが複数の中央演算処理装置を備えていることを意味します。
コンピュータに複数のコアを持つプロセッサが1つしかない場合、Pythonのマルチスレッドを使ってタスクを並列に実行することができます。
マルチプロセッサシステムは、同時に複数のプロセッサをサポートする能力を持っています。
システムで利用可能なCPUコアの数を調べるには、mp.cpu_count()関数を使用します。
今回は、Pythonのマルチプロセッシングモジュールを使用します。
Pythonのmultiprocessingモジュールを使って、プロセッサの数を求めるサンプルコードを紹介します。
import multiprocessing as mp
print(mp.cpu_count())
|
出力 12
ここでいうcountとは、複数のプロセッサのコア数を合計したものです。
このモジュールの最も重要なクラスは次の4つです。
- プロセスクラス
- ロッククラス
- キュー・クラス
- プール・クラス
これらのクラスを個別に見てみましょう。
1. プロセスクラス
プロセスは、現在のプロセスのフォークされたコピーです。
新しいプロセス識別子を作成し、タスクは独立した子プロセスとして実行されます。
start()関数やjoin()関数はこのクラスに属します。
プロセスに引数を渡すには、argsキーワードを用います。
start()関数の例
ここでは、数の平方と立方体をそれぞれ求める関数 calc_square と calc_cube を作成しました。
p1.start() と p2.start() で関数が開始され、p1.join() と p2.join() で処理が終了します。
import time
import multiprocessing
def calc_square(numbers):
for n in numbers:
print('square ' + str(n*n))
def calc_cube(numbers):
for n in numbers:
print('cube '+ str(n*n*n))
if __name__ == "__main__":
arr=[2,3,8,9]
p1=multiprocessing.Process(target=calc_square,args=(arr,))
p2=multiprocessing.Process(target=calc_cube,args=(arr,))
p1.start()
p2.start()
p1.join()
p2.join()
print("Done")
|
結果は以下の通りです。
square 4
square 9
square 64
square 81
cube 8
cube 27
cube 512
cube 729
Done |
2. ロッククラス
ロッククラスは、コードをロックすることで、ロックが解除されるまで他のプロセスが同様のコードを実行できないようにするためのクラスです。
ロックを要求するには、acquire()関数を使用し、ロックを解放するには、release()関数を使用します。
from multiprocessing import Process, Lock
lock=Lock()
def printer(data):
lock.acquire()
try:
print(data)
finally:
lock.release()
if __name__=="__main__":
items=['mobile','computer','tablet']
for item in items:
p=Process(target=printer,args=(item,))
p.start()
|
結果は以下の通りです。
mobilecomputertablet |
3. Queue クラス
QueueはFirst In First Out (FIFO)技術を使ったデータ構造で、Pythonのネイティブオブジェクトを使ったプロセス間通信を行うのに役立ちます。
キューは、パラメータとして渡されたとき、プロセスが共有データを消費することを可能にします。
put()関数はキューにデータを挿入するために使われ、get()関数はキューからデータを消費するために使われます。
import multiprocessing as mp
def sqr(x,q):
q.put(x*x)
if __name__ == "__main__":
q=mp.Queue() # Instance of queue class created
processes=[mp.Process(target=sqr,args=(i,q))for i in range (2,10)] # List of processes within range 2 to 10
for p in processes:
p.start()
for p in processes:
p.join()
result = [q.get() for p in processes]
print(result)
|
出力。
[4, 9, 16, 25, 36, 64, 49, 81]
|
4. プールクラス
プールクラスは、複数の入力値に対して関数を並列に実行することを支援します。
この概念をデータ並列処理と呼びます。
ここでは、関数呼び出しの入力として配列[5,9,8]をマップしています。
複数の引数のリストを渡すには pool.map() 関数を使用します。
import multiprocessing as mp
def my_func(x):
print(x**x)
def main():
pool = mp.Pool(mp.cpu_count())
result = pool.map(my_func, [5,9,8])
if __name__ == "__main__":
main()
|
結果は以下の通りです。
312538742048916777216 |
まとめ
今回は、Pythonのマルチプロセシングで最も重要な4つのクラス、Process、Lock、Queue、Poolについて学びました。
参考文献
モジュール公式ドキュメント