マルチスレッド処理をやってみる（Python）

# 目的
マルチスレッド処理に触れてみる（Python）
# 使用したハード・ソフト
VisualStudioCode
MacStudio
# アジェンダ
- マルチスレッドとは？？
- 今回のコード全体を簡単に解説
- ちょっと裏話

# マルチスレッドとは？？
　`マルチスレッド`と聞いてすぐに内容が思い浮かぶ非技術者は少ないと思います。
ですが「`マルチ`」という単語から何かしらを`複数`扱うのだろうということは理解できるのではないでしょうか？

### マルチスレッド
　「`マルチ`」と「`スレッド`」に分けて解説しましょう。
「`マルチ`」とは言わずもがな、複数個のものを指しますね。
「`スレッド`」とは、コンピュータが処理を行うための`一貫性のある命令の流れ`を指します。
ということで`マルチスレッド`とは、複数の命令を同時にこなすことを指すんですね。

　もう少しちゃんとした解説を見たいという方は以下のページを参考にしてみるといいと思います。

https://wa3.i-3-i.info/word12455.html

# 今回のコード全体を簡単に解説
　さて、今回は`Python`でコードを書いてみたいと思いますが、私の環境では`VSCode`による開発を行ってきます。
全く同一の環境で行う必要はありませんが、個人的には`VSCode`をお勧めしています〜

　コード本体に行く前に簡単に説明を挟みますね。
今回のコードでは`カレーライス`を料理する工程をプログラムで書いていきたいと思います。
大きく分けて二つ、「`カレーを作る`」工程と「`ご飯を炊く`」工程に分かれています。
さて、次の二人のうちどちらが良いですか？

・カレーを作り終わってからご飯を炊く人
・カレーを作りながらご飯も炊く人

効率が良さそうなのはカレーとご飯を同時に作れる人だったりしますよね。
ということで今回は同時に作れる人にしましょう。

~~~python3

import threading
import time

# カレーを作る関数
def make_curry():

    print('  カレーを作ります。')
    time.sleep(3)
    print('  カレーができました。')

# ご飯を炊く関数
def make_rice():

    print('  ご飯を炊きます。')
    time.sleep(2)
    print('  ご飯が炊けました。')

# メイン
if __name__ == "__main__":

    print('カレーライスを作ります。')

    # スレッドを作る
    thread1 = threading.Thread(target=make_curry)
    thread2 = threading.Thread(target=make_rice)

    # スレッドの処理を開始
    thread1.start()
    thread2.start()

    # スレッドの処理を待つ
    thread1.join()
    thread2.join()

    print('盛り付けます。')
    print('カレーライスができました。')
~~~

こちらが今回のコード全体になります。
見てわかるように`カレーを作る関数`・`ご飯を炊く関数`・`メイン部分`に分かれていますね。
上部二つの関数はごく普通の関数で、`マルチスレッド`のための特殊な処理は行っていません。
ということはメイン部分に`マルチスレッド`の仕組みが搭載されているわけですね。

~~~python3
import threading
import time

# メイン
if __name__ == "__main__":

    print('カレーライスを作ります。')

    # スレッドを作る
    thread1 = threading.Thread(target=make_curry)
    thread2 = threading.Thread(target=make_rice)

    # スレッドの処理を開始
    thread1.start()
    thread2.start()

    # スレッドの処理を待つ
    thread1.join()
    thread2.join()

    print('盛り付けます。')
    print('カレーライスができました。')
~~~

`マルチスレッド`を扱うために今回は`threading`というライブラリをインポートしています。
メイン部分で行なっている処理を簡単に示すと
- スレッドの作成(処理させたい内容の設定)
- スレッドの開始
- スレッドの処理待ち
という感じですね。
#### スレッドの作成
~~~python3
thread1 = threading.Thread(target=make_curry)
~~~
行なっていることとしてはthreadingのThreadという機能を使用していますね。
スレッドに行わせたい処理をtargetに記しています。（今回はmake_curry関数）
#### スレッドの開始
~~~python3
thread1.start()
~~~
スレッドに対して`スタートの命令`を出します。
ここで処理が分かれて行われることでマルチスレッドとして動作するわけですね。

#### スレッドの処理待ち
~~~python3
thread1.join()
~~~
ここでは処理が終わるのを待機していますね。
この文がないと今回のコードではカレーとご飯ができる前にカレーライスが完成してしまうわけですね。

### 実行結果
~~~
カレーライスを作ります。
  カレーを作ります。
  ご飯を炊きます。
  ご飯が炊けました。
  カレーができました。
盛り付けます。
カレーライスができました。
~~~

ということで効率よくカレーライスを作るプログラムが完成しましたね。
# ちょっと裏話
　裏話というほどでもないのですが、今回`マルチスレッド`の処理を勉強した理由として、`ドローンの多重制御`を行いたいという目的がありました。
となると、ただただマルチスレッド動作を行うだけでは処理にバグが含まれたりする可能性があるので、`threading`の`Lock()`を使用して処理を行っています。
今後`Lock（）`についての記事を書くことがあるかもしれませんが、カレーライスとご飯をそれぞれ出来上がってから次の工程に行くプログラムを以下に載せておきます。（カレー作るだけならマルチスレッドはいりませんが…）

~~~python3
import threading                                #マルチスレッドを扱うためのライブラリをインポート
import time                                     #time import

lock = threading.Lock()                         #スレッドのロックを行うためにthreadingに搭載されているLockを変数として宣言

# カレーを作る関数
def make_curry():

    with lock:                                  #以下、カレーを作っている時は誰の邪魔も入れさせないしカレー以外は作らない
        print('  カレーを作ります。')
        time.sleep(5)
        print('  カレーができました。')
         
            

# ご飯を炊く関数
def make_rice():
    
    with lock:                                  #以下、ご飯を炊いている時は誰の邪魔も入れさせないしご飯以外は炊かない
        print('  ご飯を炊きます。')
        time.sleep(2)
        print('  ご飯が炊けました。')
    

# メイン
if __name__ == "__main__":
    

    print('カレーライスを作ります。')

    # スレッドを作る
    thread1 = threading.Thread(target=make_curry)       #スレッド１にカレーを作る関数をセット
    thread2 = threading.Thread(target=make_rice)        #スレッド２にご飯を炊く関数をセット

    # スレッドの処理を開始
    thread1.start()                                     #カレー調理開始
    time.sleep(1)
    thread2.start()                                     #炊飯開始

    # スレッドの処理を待つ
    thread1.join()
    thread2.join()

    print('盛り付けます。')
    print('カレーライスができました。')
~~~

### 参考文献

https://zenn.dev/nekoallergy/articles/py-advance-threading-01

https://qiita.com/sitar-harmonics/items/a5295bf0b032d7ffcd01