Python Queueの使い方

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

エスプレッソを作ってミルクを泡立てて、久しぶりにスターバックスのマグカップを使ってラテをを入れてみたのですが、かなりボリュームがありました。

通常のコーヒーカップって200mlあるかないかくらいだと思うのですが、スタバのマグは400mlはありますからね。

単純計算で体重が0.4kg太っちゃうわけです。

案の定、体重は増えてたので、ラテを飲むときは、通常のコーヒーカップを使うようにします。

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

昨日の復習

昨日は、semaphoreについて学習しました。

通常ならロックしたスレッドの処理は一つ一つ順番に処理をしますが、semaphoreを使えば、ロックした2つ以上のスレッドを並列処理させることができました。

並列処理をさせたあと、その結果を使って別のスレッドに値を渡すという感じで使うことができました。

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

今日は、キュー(queue)を学習します。

Queue

「Queだけでいいんじゃないの?」と思ってしまうのは私だけでしょうか?

公式ドキュメントを見ると、そんなQueueには、3種類のQueueオブジェクトが用意されているようです。

  • queue.Queue(FIFOキュー)
  • queue.Lifoqueue(LIFOキュー)
  • queue.PriorityQueue(優先順位付きキュー)

今日は、この中のqueue.Queueを学習しますが、これらのQueueはリストのように値を入れて取り出すことができます。

値を入れた順番のまま取り出せるのがqueue.Queue(FIFOキュー)で、「First in First out」といわれ、最初に入れたものを最初に出します。

次のqueue.Lifoqueue(LIFOキュー)は、「Last in First out」といわれ、最後に入れたものを最初に出します。

最後のqueue.PriorityQueue(優先順位付きキュー)は、優先順位をつけて入れて、その優先順位順に取り出します。

queue.Queue

ファースト・イン・ファースト・アウトのqueue.Queueは、値を入れて取り出す処理ができるので、2つのスレッドで値をやり取りすることができます。

import logging
import queue
import threading
import time

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

def thread1(queue):
    logging.debug('start1')
    queue.put('Yes')
    time.sleep(2)
    queue.put('No')
    logging.debug('end1')

def thread2(queue):
    logging.debug('start2')
    logging.debug(queue.get())
    logging.debug(queue.get())
    logging.debug('end2')

if __name__ == '__main__':
    queue = queue.Queue()
    t1 = threading.Thread(target=thread1, args=(queue, ))
    t2 = threading.Thread(target=thread2, args=(queue, ))
    t1.start()
    t2.start()

locksemaphoreと同じように、22行目でqueueオブジェクトを作成しています。

23行目、24行目のargsの引数にはqueueを指定して、8行目、15行目のスレッド関数の引数にもqueueを指定しています。

あとは、thread1putを使ってYesNoを入れて、thread2getqueueに入れた順番に出力しています。

time.sleepは、動作がわかりやすいように入れていますが、実際に使うときは必要ありません。

このコードの実行結果は次のようになります。

Thread-1: start1
Thread-2: start2
Thread-2: Yes  #この行の出力後、2秒後に次の行が出力される
Thread-1: end1
Thread-2: No
Thread-2: end2

thread1thread2は並列処理がされるので、9・10行目、16・17行目が処理されて、実行結果の3行目まで出力されたあと、11行目のtime.sleepによって、2秒待ちます。

この間、thread2の18行目queue.get()は、queueに2つ目の値がputされるのを待機した状態になっています。

2秒後にthread1の12行目でNoqueueに入れられると同時に18行目のgetNoが出力されています。

lockされたスレッドの終了を待っている次のスレッドのような感じですね。

似たような感じ

lockにしてもsemaphoreにしてもqueueにしても処理的には似たような感じがします。

この微妙な違いを理解して使い分けられるようになるには、やはり数をこなすしかないと思うので、地道にコードを書いていくしかないのが現実です。

かのアインシュタインもこのように言ってますよね。

何かを学ぶのに、自分自身で経験する以上に良い方法はない

経験を積み重ねていきましょう!

それでは明日もGood Python!