Raspberry Pi & Python 開発ブログ ☆彡

Raspberry PiとPythonの基本的な使い方をわかりやすく解説。初心者、入門者必見!!

python3:concurrent.futuresでMultiProcess(プロセス)を生成する

multiprocess basic

ブログ管理者のP.Hです!

下記の記事でconcurrent.futuresをモジュールを使用して、マルチスレッドで動かす方法を紹介しました。今回は、マルチプロセスで動かす方法を紹介したいと思います。

www.raspberrypirulo.net

それでは、multiprocessの実装方法を紹介します。

multiprocessingモジュールでプロセス生成する

まずは、比較のために今までのやり方を紹介しようと思います。大きく2パターンあります。

  1. プロセスにしたい関数を引数に与えて、multiprocessingモジュールをインスタンス化 ⇒ start()
    2.multiprocessingモジュールを継承したクラスのrun関数にコードを記載、クラスをインスタンス化 ⇒ start()

簡単ですが、サンプルを記載しておきます。

import multiprocessing
import time
from datetime import datetime

class MyProcess1: # 上記の1のやり方

    def __init__(self, name):
        self.name = name

    def start(self):

        t = multiprocessing.Process(target = self.run, args = (self.name,) ) # 引数にプロセス生成したい関数を与える
        t.start() # プロセス生成

    def run(self, name): # self.nameを使えば、引数のnameは不要。コードの書き方のサンプルとして引数を使っています。
        while True:
            print('[{0}] : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), name) )
            time.sleep(1)

class MyProcess2(multiprocessing.Process):  # 上記の2のやり方

    def __init__(self, name):
        multiprocessing.Process.__init__(self)
        self.name = name

    def run(self): # run関数にプロセス化したいコードを書く
        while True:
            print('[{0}] : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.name) )
            time.sleep(2)

if __name__ == "__main__":
    
    myprocess1 = MyProcess1("MyProcess1")
    myprocess1.start()
    myprocess2 = MyProcess2("MyProcess2")
    myprocess2.start() # プロセス生成

concurrent.futures のProcessPoolExecutorでプロセス生成する

それでは、新しい方法を紹介します。concurrent.futuresパッケージのProcessPoolExecutorモジュールを使って、プロセス生成する方法です。起動時に複数プロセスを一気に生成するようなとき、とてもわかりやすいです。

from concurrent.futures import ProcessPoolExecutor
import time
from datetime import datetime

class MyProcess1:

    def __init__(self, name):
        self.name = name

    def run(self):
        while True:
            print('[{0}] : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.name) )
            time.sleep(1) # 1秒ごとにprint文を表示

class MyProcess2:

    def __init__(self, name):
        self.name = name

    def run(self):
        while True:
            print('[{0}] : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.name) )
            time.sleep(2) # 2秒ごとにprint文を表示

if __name__ == "__main__":
    
    process_pool = [] # プロセス生成したい関数を登録
    process_pool.append(MyProcess1("MyProcess1").run) # MyProcess1のrun関数をリストに追加
    process_pool.append(MyProcess2("MyProcess2").run) # MyProcess2のrun関数をリストに追加
        
    with ProcessPoolExecutor(max_workers=2) as executor: # max_workerは同時に動かすプロセスの最大数 Noneを指定するとコア数 * 4の値になる
        for process in process_pool:
            results = executor.submit(process) # submit関数で、list内の関数をプロセス生成
        for result in results:
            print(result)

結果は、以下のようになります。MyProcess1は1秒おきに、MyProcess2は2秒おきにメッセージが表示されます。並列処理されているのがわかると思います。

[2019-12-11 10:29:21] : MyProcess1
[2019-12-11 10:29:21] : MyProcess2
[2019-12-11 10:29:22] : MyProcess1
[2019-12-11 10:29:23] : MyProcess2
[2019-12-11 10:29:23] : MyProcess1
[2019-12-11 10:29:24] : MyProcess1
[2019-12-11 10:29:26] : MyProcess2
[2019-12-11 10:29:26] : MyProcess1
[2019-12-11 10:29:27] : MyProcess1

ProcessPoolExecutorの部分をThreadPoolExecutorに変えるとマルチプロセスになります。 ProcessPoolExecutorの場合、ps -efコマンドで確認すると、プロセスが3つ立ち上がります。ThreadPoolExecutorの場合は、プロセスが1つだけ立ち上がります。ProcessPoolExecutorの時に、マルチプロセスで動作しているのが確認できます。

マルチプロセスの場合は、 プロセス間でデータをやりとり方法は、下記記事を参考にしてください。

www.raspberrypirulo.net

ラズパイ ソフトウェアに戻る
トップページに戻る