Pythonのthreadingモジュール

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

先日釣りに行ったときに、突然のゲリラ雨にあいました。

幸い事前にWeatherNewsの雨雲レーダーで確認していたので、降ってきそうになったときに橋の下に逃れることができたのですが、そこにあったベンチに座っていたときに心臓が飛び出るくらいびっくりすることがありました。

それが、ムカデ!?

腕がなにかムズムズするなと思ってみてみると、なんだか長いものが動いているんです。

とっさに叫んで振り払うも服に付いたままで上に登ってこようとするので、シャツを脱ぎかけながらバタバタするととりあえずどこかにとんでいったようでした。

暗かったので、ムカデなのかフナムシなのかはっきりとはわかりませんでしたが、ほんと冷や汗出まくりのハプニングでした。

橋の下に設置されている椅子には注意しましょう。

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

昨日の復習

昨日は、マルチスレッドとマルチプロセスの概念について学習してきました。

スレッドはメモリに保存した情報を共有するので、処理スピードは速いもののクラッシュしたときにすべてのスレッドに影響が起こってしまいます。

一方でプロセスは、一つのコアが一つのプロセスを処理して、メモリを共有することはないので、一つのプロセスがクラッシュしても他のプロセスに影響を与えることはありません。

詳細については昨日の記事をごらんください。

今日は、threadingモジュールの基本的な使い方について学習します。

threadhing

実際のスレッドを動かすコードを書いてみます。

import threading
import time


def thread1():
    print(threading.currentThread().getName(), 'start')
    time.sleep(5)
    print(threading.currentThread().getName(), 'end')

def thread2():
    print(threading.currentThread().getName(), 'start')
    time.sleep(5)
    print(threading.currentThread().getName(), 'end')

if __name__ == '__main__':
    t1 = threading.Thread(target=thread1)
    t2 = threading.Thread(target=thread2)
    t1.start()
    t2.start()
    print('started')

最初にthreadingモジュールをインポートします。

timeモジュールも動きがわかりやすいようにインポートして使います。

関数は、threadingでスレッドの名前とstartを出力したあとtime.sleep(5)で5秒待ってから再度スレッドの名前とendを出力するものです。

この関数を2つ作って、15行目から20行目で__main__のときに、thread1thread2t1t2に代入してスタートさせたあと、startedを出力しています。

実行結果

Thread-1 start
Thread-2 start
started
Thread-1 end
Thread-2 end

3行目のstartedを出力したあと5秒経過してから残りの行が出力されます。

スレッドの処理は、順番に処理されるのではなく、同時進行の並列処理がされているので、タイミングによっては、Thread-1Thread-2の出力が入れ替わることがあります。

loggingで出力

print出力ではなく、loggingで出力する方法があります。

それぞれを出力するスレッドを作るコードを書いてみます。

import logging
import threading
import time

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

def thread3():
    logging.debug('start3')
    time.sleep(3)
    logging.debug('end3')

def thread():
    print(threading.currentThread().getName(), 'start')
    time.sleep(5)
    print(threading.currentThread().getName(), 'end')

if __name__ == '__main__':
    t1 = threading.Thread(target=thread)
    t3 = threading.Thread(target=thread3)
    t1.start()
    t3.start()
    print('started')

logginモジュールをインポートして、5行目、6行目でレベルをDEBUGに指定して、スレッド名とメッセージを出力するログを指定します。

8行目から11行目でデバッグによる出力をする関数を記述していますが、time.sleepは3秒に指定しています。

13行目から16行目は最初のprint出力スレッドと同じコードです。

18行目からは実行コードですが、20行目と22行目をロギングのt3に変更しています。

実行結果

Thread-1 start
started
Thread-2: start3
Thread-2: end3
Thread-1 end

3行目のThead-2: start3まで出力したあと、3秒後に4行目が、その2秒後に5行目が出力されます。

並列処理なので、メインコードの21行目から23行目の出力である1行目から3行目は順番が入れ替わっています。

並列処理

並行処理は、一つ一つの処理が順番に処理されていくので出力の順番はコードの記述順のままですが、並列処理は同時進行で処理されるので、コードの記述順通りに出力されるわけではありません。

今回のコードを何度か実行してみるとわかるのですが、time.sleepが入る前までは出力される順番が入れ替わったりします。

これはレクチャーをみているだけではわからないことで、自分でコードを書いて何度か出力してみてわかることです。

実際に試してみて、理解できることはたくさんあるので、何度も試して変な?!出力にならないかチェックしてみてください。

それでは明日もGood Python!