どーもこんにちはKeita_Nakamori(´・ω・`)です。
最近はIoT関係で遊んでいるのですが、1つのラズパイで、複数のセンサーを扱うにはどうすればいいか考えていました。
普通のシングルスレッドで実行すると、PLCでいうところのスキャンタイムに依存することになります。
あるセンサーは高速でパルスをカウントしなければならない一方で、別のセンサーは、1秒周期でいいよとか、サンプリングタイムが全然違う場合はどうすればいいのか。
解決策として、マルチスレッドというものがあります。
それぞれのセンサーでサンプリングする関数を作って、それぞれを別々のスレッドとしてオブジェクト化して、メインスレッド内で実行するというやり方です。そうすると、それぞれのスレッドが互いに干渉することなく、あたかも2つのプログラムが同時に動いているような挙動を示します。
今回は、IOTというより、Pythonの基本なので、カテゴリーはPythonにしました。
では、やってみましょう。
まずは普通の関数を実行
まず最初に time_count()という関数を作って実行してみましょう。
1秒ごとに現在時間を出力しているだけのスクリプトです。
Pythonではthreadingモジュールから利用することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import datetime import time def time_count(): print("time count start") cnt=0 while True: now = datetime.datetime.now() print(now) cnt+=1 time.sleep(1) if cnt > 10: print(" time is dead") break print("finished") time_count() |
結果:どうでしょう、これは普通ですよね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
time count start 2019-06-03 22:16:48.919908 2019-06-03 22:16:49.919994 2019-06-03 22:16:50.920481 2019-06-03 22:16:51.920590 2019-06-03 22:16:52.920871 2019-06-03 22:16:53.921354 2019-06-03 22:16:54.922110 2019-06-03 22:16:55.922260 2019-06-03 22:16:56.922273 2019-06-03 22:16:57.922571 2019-06-03 22:16:58.923210 time is dead finished |
次は、これをスレッド化して実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import datetime import time def time_count(): print("time count start") cnt=0 while True: now = datetime.datetime.now() print(now) cnt+=1 time.sleep(1) if cnt > 10: print("time is dead") break print("finished") thread_001 = threading.Thread(target=time_count) thread_001.start() |
最後の2行で、関数をスレッドとしてオブジェクト化し、スタートさせています。
動作は、全く一緒です。
そして、次はマルチスレッドを試してみましょう。
今度は2つのスレッドを同時に動かしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import threading import datetime import time def time_count(): print("time count start") cnt=0 while True: now = datetime.datetime.now() print(now) cnt+=1 time.sleep(1) if cnt > 10: print("time is over") break print("time count is done") def time_alert(): print("ready to alert") time.sleep(5) print("get up now!!") print("end of alert") thread_001 = threading.Thread(target=time_count) thread_002 = threading.Thread(target=time_alert) thread_001.start() thread_002.start() print("here is script end") |
結果:さあどうでしょうか。
thread_001とthread_002をスタートして、最後に”here is script end”をするスクリプトです。
thread_001が始まった直後にthread_002もスタートしていますので、スクリプト通り、thread_001による時間カウントが5秒のところで”get up now!!”というthread_002の出力が確認できます。
さらに、スクリプトの最後の”here is script end1”はthread_002がスタートされた直後に終了しています。
メインスレッドが最後までいっても、thread_001、thread_002が終わっていなければ、プログラムは終わりません。このように、実は3つのスレッドが同時に走っているわけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
time count start 2019-06-03 22:22:18.637921 ready to alert here is script end 2019-06-03 22:22:19.638316 2019-06-03 22:22:20.639319 2019-06-03 22:22:21.640172 2019-06-03 22:22:22.641065 get up now!! end of alert 2019-06-03 22:22:23.641760 2019-06-03 22:22:24.642122 2019-06-03 22:22:25.642486 2019-06-03 22:22:26.642826 2019-06-03 22:22:27.643360 2019-06-03 22:22:28.644210 time is over time count is done |
最後に
関数をメソド化して使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# 最後に 関数をメソド化してみる import threading import datetime import time class time_ruler(): def time_count(self): print("time count start") cnt=0 while True: now = datetime.datetime.now() print(now) cnt+=1 time.sleep(1) if cnt > 10: print("time is over") break print("time count is done") def time_alert(self): print("ready to alert") time.sleep(5) print("get up now!!") print("end of alert") # インスタンス作成 time_master = time_ruler() # メソドをスレッドにする。 thread_001 = threading.Thread(target=time_master.time_count) thread_002 = threading.Thread(target=time_master.time_alert) # スレッドをスタート thread_001.start() thread_002.start() print("script is over") |
動作は一緒です。以上です。