Python学習【365日チャレンジ!】213日目のマスターU(@Udemy11)です。
この間、かなり近くでトンビをみました。
最初はカラスかなと思っていたのですが、近づいてみるとくちばしがかっこよく曲がったトンビだったので、写真を撮ったのですが、近づきすぎたみたいですぐに飛んでいってしまいました。
10匹くらいいて、近づくと飛んでいくんですが、羽を広げるとかなり大きいのでびっくりしました。
「トンビが鷹を生む」なんて言葉がありますが、個人的にはどっちがどっちやら見分けがつかないので、トンビと鷹でそんな差があるのかな?なんて思っちゃいます。
それでは、今日もPython学習をはじめましょう。
昨日の復習
昨日は、queueついて学習しました。
Queue
にはファーストインファーストアウトとラストインファーストアウト、優先順位付きの3つの種類がありました。
リストのように値を入れて、入れた順番に値を出していくのがファーストインファーストアウトで、スレッドに値を入れて、ちがうスレッドで入れた順番に出力していくことができました。
並列処理になるので、値を入れると同時に出力されますが、出力する方は、値が入力されていないからといって、スレッドを終了することなく、値が入力されるのを待機して、入力されてから出力処理を行っていました。
詳細については、昨日の記事をごらんください。
今日は、キュー(queue)のもう少し高度な使い方を学習します。
Whileループを使う
昨日は、一つのスレッドに値を入れて別のスレッドでその値を取り出しましたが、今回は、メインのスレッドで10個値を入れてオブジェクト化したスレッドで、while
ループを使って取り出してみます。
import logging
import queue
import threading
logging.basicConfig(level=logging.DEBUG, format='%(threadName)s: %(message)s')
def thread1(queue):
logging.debug('start1')
while True:
item = queue.get()
if item is None:
break
logging.debug(item)
logging.debug('end1')
if __name__ == '__main__':
queue = queue.Queue()
for i in range(10):
queue.put(i)
t1 = threading.Thread(target=thread1, args=(queue, ))
t1.start()
queue.put(None)
9行目から13行目でwhile
ループを使って、18行目、19行目でqueue
に入れた値を取り出しています
while
ループを終了するのは、queue
にNone
が入っていた場合にして、最後の22行目でqueue
にNone
を代入しています。
このコードの実行結果は次のとおりです。
Thread-1: start1
Thread-1: 0
Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-1: 4
Thread-1: 5
Thread-1: 6
Thread-1: 7
Thread-1: 8
Thread-1: 9
Thread-1: end1
最初と最後には、start1
とend1
が出力されています。
間には、for
ループで代入したqueue
の値をwhile
ループで取り出しているのがわかります。
ちなみに最後の22行目のqueue.put(None)
の記述がないと9行目のqueue.get()
で値の入力を待った状態になるので、いつまで立ってもスレッドが終了しません
queueのtask_doneとjoin
非常に長い処理をqueue
の処理が終了したあとにさせたい場合は、queue
の終了を待つコードを入れなければなりません。
def thread1(queue):
logging.debug('start1')
while True:
item = queue.get()
if item is None:
break
logging.debug(item)
queue.task_done()
logging.debug('very long work')
logging.debug('end1')
if __name__ == '__main__':
queue = queue.Queue()
for i in range(10):
queue.put(i)
t1 = threading.Thread(target=thread1, args=(queue, ))
t1.start()
logging.debug('tasks are still working')
queue.join()
logging.debug('tasks are finished')
queue.put(None)
t1.join()
17行目の処理が非常に時間がかかるので、while
ループの処理が必ず終了してから行う場合は、スレッドでも使うjoin
を使います
queue
でjoin
を使う場合は、15行目のtask_done
を使用します。
これでqueue
に入れた値がすべて使われて、28行目のtasks are finished
が出力されたあと、再びqueue
にNone
が代入されて、10行目のwhile
ループがようやく終了するという感じです。
ちなみに31行目のt1.join()
は、不要なのですが、明示的に記述しています。
実行結果
Thread-1: start1
MainThread: tasks are still working
Thread-1: 0
Thread-1: 1
Thread-1: 2
Thread-1: 3
Thread-1: 4
Thread-1: 5
Thread-1: 6
Thread-1: 7
Thread-1: 8
Thread-1: 9
MainThread: tasks are finished
Thread-1: very long work
Thread-1: end1
この結果はきれいに順番がわかりやすいように出力されていますが、2行目のMainThread: tasks are still working
は、出力の順番が変わることがあります。
MainThread
の処理が終了したあと、処理に時間がかかるコードが読み込まれて最終end1
が出力されています。
単体では理解できない
処理が複雑でいまいち理解できていないかと思います。
私自身頭が整理できておらず、なんとなくこんな感じなのかな程度しか理解できていないので、理解するまでにもう少し時間が必要です。
今回学習した内容だけで理解するのではなく、これまでに学習してきた内容を踏まえた上であれば理解できるようになるもの早いのかなと思います。
とにかく同じようなコードを繰り返し反復練習することが重要なので、コードをコメントアウトしたり、追加したりしていろいろと試してみてください。
わからなかったことがふとした拍子に理解できるようになるかもしれませんよ。
それでは明日も、Good Python!