Raspberry Pi & Python 開発ブログ ☆彡

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

python3:concurrent.futuresでThread(スレッド)を生成する

thread basic

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

Python3.2で追加されたconcurrent.futures パッケージを使って、Threadを実装することができるようになりました。マルチスレッドとマルチプロセスの切り替えが簡単にできたり、こちらが主流になっていくと思いますので、使い方を紹介したいと思います。

それでは、threadの実装方法を紹介していきます。

Threadingモジュールでスレッド生成する

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

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

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

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

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

    def start(self):

        t = threading.Thread(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 MyThread2(threading.Thread):  # 上記の2のやり方

    def __init__(self, name):
        threading.Thread.__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__":
    
    mythread1 = MyThread1("MyThread1")
    mythread1.start()
    mythread2 = MyThread2("MyThread2")
    mythread2.start() # スレッド生成

concurrent.futures のThreadPoolExecutorでスレッド生成する

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

from concurrent.futures import ThreadPoolExecutor 
import time
from datetime import datetime

class MyThread1:

    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 MyThread2:

    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__":
    
    th_pool = [] # スレッド生成したい関数を登録
    th_pool.append(MyThread1("MyThread1").run) # MyThread1のrun関数をリストに追加
    th_pool.append(MyThread2("MyThread2").run) # MyThread2のrun関数をリストに追加
        
    with ThreadPoolExecutor(max_workers=2) as executor: # max_workerは同時に動かすスレッドの最大数 Noneを指定するとコア数 * 4の値になる
        for th in th_pool:
            results = executor.submit(th) # submit関数で、list内の関数をスレッド生成
        for result in results:
            print(result)

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

[2019-11-29 10:34:43] : MyThread1
[2019-11-29 10:34:43] : MyThread2
[2019-11-29 10:34:44] : MyThread1
[2019-11-29 10:34:45] : MyThread1
[2019-11-29 10:34:45] : MyThread2
[2019-11-29 10:34:46] : MyThread1
[2019-11-29 10:34:47] : MyThread2
[2019-11-29 10:34:47] : MyThread1
[2019-11-29 10:34:48] : MyThread1

ThreadPoolExecutor の部分をProcessPoolExecutorに変えるとマルチプロセスになります。簡単に切り替えることができますが、マルチプロセスの場合は、 データのやりとりの部分で実装を変える必要が出てくるはずです。

pythonに戻る
トップページに戻る