Pythonのマルチスレッド処理:threading, multiprocessing

Pythonでthreadingとmultiprocessingを使って並列処理を行う方法を紹介します。

threading による並列処理

時間のかかる独立した操作を並列処理したいとき、Pythonにはthreadingモジュールが用意されています。Threadクラスのコンストラクタでキーワード引数 target に対して、実行したい関数を渡します。

import threading
 
def compute():
    x = 0
    times = 2 ** 26
    while x < times:
        x += 1
 
th1 = threading.Thread(target=compute)
th2 = threading.Thread(target=compute)

th1.start(); print '1 started.'
th2.start(); print '2 started.'

th1.join(); print '1 completed.'
th2.join(); print '2 completed.'

start() メソッドを呼び出すと、実行が開始されます。計算結果が出るまで待つためには join() メソッドを使います。

実行時間を比較する

さきほどのcompute()関数を以下の2つの方法で実行してみます。

  1. 連続して2回呼び出す(sample1.py)
  2. 2つの Threadオブジェクトに渡して実行する(sample2.py)

2つの方法でそれぞれ実行時間を比較してみると、以下のような結果になりました。

$ time python sample1.py
1 started.
2 started.
1 completed.
2 completed.

real 0m6.281s

$ time python sample2.py
main started.
1 started.
2 started.
1 completed.
2 completed.

real 0m8.717s

実行時間は環境によって異なりますが、並列処理にしたはずですが、余計に時間がかかっています。これはCPythonのインタプリタでは1度に1つのスレッドしか実行されないことが原因です。本当に期待する効果を得るためには、threadingの代わりにmultiprocessingモジュールを使う必要があります。

multiprocessingによる並列処理

multiprocessingではクラス名はThreadの代わりにProcessとなります。メソッドについてはThreadクラスと同様に start()とjoin()を使うことができます。

import multiprocessing
 
def compute():
    x = 0
    times = 2 ** 26
    while x < times:
        x += 1
 
th1 = multiprocessing.Process(target=compute)
th2 = multiprocessing.Process(target=compute)

th1.start(); print '1 started.'
th2.start(); print '2 started.'

th1.join(); print '1 completed.'
th2.join(); print '2 completed.'

実行結果は次のようになりました。

$ time python sample_multiprocessing.py
1 started.
2 started.
1 completed.
2 completed.

real 0m3.559s

threadingモジュールの場合と比較すると、時間が短縮されたことがわかります。

今回の例ではthreadingは効果がありませんでしたが、公式ドキュメントによると、threadingは複数の I/O 処理を伴う場合などに有効だとされています。一方、multiprocessingではマルチコアプロセッサを活用して計算を行うことができます。


イベント

2017/12/05(火)
Design Thinking Square