ブログ管理者のP.Hです!
Python3.2で追加されたconcurrent.futures パッケージを使って、Threadを実装することができるようになりました。マルチスレッドとマルチプロセスの切り替えが簡単にできたり、こちらが主流になっていくと思いますので、使い方を紹介したいと思います。
それでは、threadの実装方法を紹介していきます。
Threadingモジュールでスレッド生成する
まずは、比較のために今までのやり方を紹介しようと思います。大きく2パターンあります。
- スレッドにしたい関数を引数に与えて、Threadモジュールをインスタンス化 ⇒ start()
- 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に変えるとマルチプロセスになります。簡単に切り替えることができますが、マルチプロセスの場合は、 データのやりとりの部分で実装を変える必要が出てくるはずです。