Python スレッドのsemapore

Python学習【365日チャレンジ!】211日目のマスターU(@Udemy11)です。

台風が過ぎ去ったので、最近タチウオの釣果が好調だというポイントに行ってきました。

ポイントに到着すると、電気ウキがネオンのように水面に連なっていてびっくり!!ほんと釣りブームが来てますね。

とりあえずなんとか空いている場所を確保してスタートしたのですが、まったくもって無反応。。。

少し粘ったのですが、一向に反応がないので早めに引き上げてきました。

一度、釣れすぎて困るってくらい釣りたいものです。

それでは、今日もPython学習をはじめましょう。

昨日の復習

昨日は、スレッドのRLockについて学習しました。

withステートメントを使ってlockしたスレッドの中で、入れ子にしたlockを扱えるようにするのがRLockでした。

通常、lockしてrequireしたスレッドは、releaseしないと入れ子のlockしたスレッドはスタートしませんが、RLockを使うことで、入れ子のロックしたスレッドを処理をスタートさせることができました。

詳しくは昨日の記事をごらんください。

今日は、スレッドのセマフォを学習します。

semaphoreとは

semaphoreは、手信号、信号装置という意味がありますが、Pythonにおいて、並列処理を行っても問題の無いスレッドの数を指定して並行処理ができ瑠要にするものです。

lockと同じように排他制御ができますが、lockが1つのスレッドに対して、semaphoreは複数のスレッドの排他制御を行うことができます。

排他制御は、Excelなどにたとえると、共有フォルダに置いたファイルを2人の人が同時に開こうとすると、後からアクセスした人は読み込み専用になるようなものですね。

一方で、Googleスプレッドシートのように、複数の人が同時に編集することが可能なプログラムもあります。

Googleスプレッドシートがどのようにして同時編集を可能にしているのかわかりませんが、通常、編集しているものを他の人が編集できちゃうと困っちゃいますよね。

semaphoreの使い方

semaphoreの使い方は、locksemaphoreに変更するだけで使えますが、排他制御をおこなうスレッドの数が引数になり、1以上の整数を引数にとります。

import logging
import threading
import time


logging.basicConfig(
   level=logging.DEBUG, format='%(threadName)s: %(message)s')

def thread1(semaphore):
   logging.debug('start1')
   time.sleep(1)
   logging.debug('finish1')

def thread2(semaphore):
   logging.debug('start2')
   time.sleep(1)
   logging.debug('finish2')

def thread3(semaphore):
   logging.debug('start3')
   time.sleep(1)
   logging.debug('finish3')

if __name__ == '__main__':
   semaphore = threading.Semaphore(2)
   t1 = threading.Thread(target=thread1, args=(semaphore, ))
   t2 = threading.Thread(target=thread2, args=(semaphore, ))
   t3 = threading.Thread(target=thread3, args=(semaphore, ))
   t1.start()
   t2.start()
   t3.start()

9行目、14行目、19行目でスレッドの引数にsemaphoreを代入していますが、代入するsemaphoreは25行目で定義しています。

26行目から28行目のThreadオブジェクトの作成の際にも、argssemaphoreを指定しています。

このコードを実行すると、thread1thread2が実行されて、1秒後に処理が終了した後thread3が実行される形になります。

thread-1: start1
thread-2: start2  #1秒後に次の3行が出力される
thread-1: finish1
thread-2: finish2
thread-3: start3  #1秒後に次の行が出力される
thread-3: finish3

実際にコードを書いて実行してみてほしいのですが、thread1thread2が並列処理されたあとロックがリリースされ、最後にthread3が実行されます。

並列処理をしてもかまわないスレッドと排他制御が必要なスレッドに分けて実行するような場面で使いますが、実践で使わないとなかなかイメージが難しい気がします。

コードを書く

コードを書くというよりタイプするといった方が正確ですが、同じコードがあるとついついコピーペーストしてしまいますが、コードになれないうちは、できるだけタイプした方がいいと思います。

同じコードをタイプするのとコピペするのでは、脳への刷り込み回数が全く違ってきます。

タイプすることで、何度も脳にインプットされるので、復習する時などもコードを覚えていたりしますが、コピペしていると思い出せなかったりします。

もちろんタイピングのスピードも速くなるので、コードを覚えられていないときは、面倒でもタイプするようにしましょう。

それでは明日もGood Python!