(最終更新月:2023年6月)
✔当記事が対象とする読者
「PythonのQueueって何だろうか?」
「PythonのQueueの使い方を学びたい」
「PythonのQueueを活用した実例を確認したい」
✔当記事で伝える内容
- PythonのQueueの概要
- PythonのQueueの使い方とその応用
- PythonのQueueを活用した具体例
当記事では、PythonのQueueの基本概念から始め、さまざまなオプションを駆使した応用方法までを、具体例を交えながら詳細に解説しています。
ぜひ最後までお読みください。
キュー:基本概念と種類
こちらでは、キューの基本的な概念と、それに関連するさまざまな種類について解説します。
PythonのQueueモジュールに限らず、一般的なQueueの概念について理解しましょう。
- FIFOキュー(先入れ先出し)
- LIFOキュー(後入れ先出し)
- 優先度付きキュー
FIFOキュー(先入れ先出し)
FIFO(First In, First Out)キューは、最も一般的なキューの形式です。
この形式では、キューに最初に追加された要素が最初に取り出されます。
人々が行列に並んで待つ様子に似ており、最初に来た人が最初にサービスを受けるという考え方です。
例えば、プリンターのジョブキューは通常、FIFO方式で処理されます。
LIFOキュー(後入れ先出し)
LIFO(Last In, First Out)キューは、スタックとも呼ばれ、最後に追加された要素が最初に取り出されるデータ構造です。
これは一般的に、物事を積み重ねていくイメージに近いでしょう。
たとえば、皿を積み重ねていった場合、最後に追加された皿(一番上)が最初に取り出されます。
優先度付きキュー
優先度付きキューでは、各要素が一定の優先度を持っているもの。
優先度が高い要素が最初に取り出されるのが特徴です。
一般的な生活の中で例を挙げると、病院の緊急室での患者の処理がこれに相当します。
患者は到着順ではなく、病状の重さ(つまり「優先度」)に基づいて処理されます。
Queueモジュール:主要なクラスとメソッド
Queueモジュール内には、キューを操作するための多くのクラスとメソッドが存在します。
ここでは、その主要なものを紹介します。
- Queueモジュールのインポート
- キューの生成(Queueクラス)
- キューへの要素追加(putメソッド)
- キューからの要素取り出し(getメソッド)
- キューの要素数を数える
- メソッド一覧
Queueモジュールのインポート
PythonのQueueモジュールを使用するためには、まずそれをインポートする必要があります。
以下がそのインポート方法です。
import queue
これにより、Queueモジュール内のクラスや関数を利用できるようになります。
確かめたい方はこちらをどうぞ。
>>> queue
<module 'queue' from '/usr/lib/python3.8/queue.py'>
キューの生成(Queueクラス)
Queueモジュールには、キューを作成するためのQueueクラスが含まれています。
Queueクラスをインスタンス化することで、新たなキューの作成が可能です。
q = queue.Queue()
この時点でq
は空のFIFOキューとなり、これ以降で追加した要素を保存できます。
キューへの要素追加(putメソッド)
Queueクラスのインスタンスに対して、put
メソッドを使うことで新たな要素をキューの末尾に追加できます。
puメソッドの引数に追加したい要素を指定してください。
q.put("apple")
このコードにより、文字列"apple"
がキューq
に追加されます。
キューからの要素取り出し(getメソッド)
キューから要素を取り出すには、getメソッドを使いましょう。
get
メソッドはキューから最初の要素(FIFOキューの場合は最も古い要素)を削除し、その要素を返します。
item = q.get()
このコードにより、キューq
から最初の要素が取り出され、その要素が変数item
に代入されます。
キューの要素数を数える
キューの要素数を数えるには、qsizeというメソッドがあります。
いくつのキューが格納されているかを数えられるメソッドです。
q.put('test1')
q.qsize()
#出力
#1
q.get()
#出力
#'test1'
q.qsize()
#出力
#0
メソッド一覧
以下は、queue
モジュールのメソッドの一覧です。
メソッド名 | 説明 | 例 |
---|---|---|
all_tasks_done() | 全てのタスクが完了したかどうかを判定する | if q.all_tasks_done(): |
empty() | キューが空かどうかを判定する | if q.empty(): |
full() | キューが満杯かどうかを判定する | if q.full(): |
get() | キューからアイテムを取得する | item = q.get() |
get_nowait() | キューからアイテムを取得する(非ブロッキング) | item = q.get_nowait() |
join() | キュー内の全てのタスクが完了するまでブロックする | q.join() |
maxsize | キューの最大サイズ | q.maxsize |
mutex | キューのロックオブジェクト | q.mutex |
not_empty | キューが空でないことを示す条件変数 | q.not_empty |
not_full | キューが満杯でないことを示す条件変数 | q.not_full |
put(item) | アイテムをキューに追加する | q.put(10) |
put_nowait(item) | アイテムをキューに追加する(非ブロッキング) | q.put_nowait(20) |
qsize() | キュー内のアイテム数を取得する | size = q.qsize() |
queue | キューオブジェクト | q = queue.Queue() |
task_done() | ワーカースレッドがタスクの完了を示すために呼び出す | q.task_done() |
unfinished_tasks | 完了していないタスク数 | q.unfinished_tasks |
これらのメソッドを使用することで、queue
モジュールを効果的に操作することができます。
実践:Queueモジュールの使い方
ここでは、具体的なコード例を通じて、Queueモジュールの使い方を具体的に見ていきましょう。
- FIFOキューのサンプルコード
- LIFOキューのサンプルコード
FIFOキューのサンプルコード
以下に、Queueモジュールを使ってFIFOキューを操作する基本的なコードを示します。
import queue
# FIFOキューの生成
q = queue.Queue()
# キューへの要素追加
q.put("apple")
q.put("banana")
q.put("cherry")
# キューからの要素取り出し
while not q.empty():
print(q.get())
このコードを実行すると、"apple"
, "banana"
, "cherry"
の順番で要素が取り出され、それぞれが表示されます。
LIFOキューのサンプルコード
次に、QueueモジュールのLifoQueueクラスを使ってLIFOキューを操作する基本的なコードを示します。
import queue
# LIFOキューの生成
q = queue.LifoQueue()
# キューへの要素追加
q.put("apple")
q.put("banana")
q.put("cherry")
# キューからの要素取り出し
while not q.empty():
print(q.get())
このコードを実行すると、"cherry"
, "banana"
, "apple"
の順番で要素が取り出され、それぞれが表示されます。
これは、最後に追加した要素から順に取り出されているためです。
PythonのQueueモジュールとマルチスレッド
Queueモジュールは、Pythonのマルチスレッド環境でも安全にデータを交換するために使用できます。
次の節ではその詳細を見ていきましょう。
- マルチスレッドでキューを使う利点
- マルチスレッドでのキューの利用例
マルチスレッドでキューを使う利点
Queueモジュールを活用すると、スレッド間でデータを安全にやり取りできるようになります。
なぜならマルチスレッドでのデータの競合や不整合に対して、データの待ち行列(キュー)を提供できるから。
ひとつのスレッドがキューにデータを入れ、他のスレッドでそのデータを取り出します。
結果としてデータは一度に一つのスレッドだけが扱うことになり、データの競合を防げるのです。
import queue
import threading
def producer(q, items):
for item in items:
q.put(item)
print("Produced:", item)
q.put(None) # 終了を示すためにNoneを追加
def consumer(q):
while True:
item = q.get()
if item is None:
break # 終了を示すNoneを取得したらループを終了
print("Consumed:", item)
q = queue.Queue() # スレッドセーフなキューオブジェクトの作成
# データを生産するスレッド
producer_thread = threading.Thread(target=producer, args=(q, [1, 2, 3, 4, 5]))
producer_thread.start()
# データを消費するスレッド
consumer_thread = threading.Thread(target=consumer, args=(q,))
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
Queueモジュールのメソッドがスレッドセーフであるという特徴もあります。
複数のスレッドが同時にQueueオブジェクトのメソッドを呼び出しても、内部の状態が適切に保たれることを保証してくれるのです。
マルチスレッドでのキューの利用例
ここでは、マルチスレッド環境でキューを使用する簡単な例を紹介します。
ひとつのプロデューサースレッドがキューにデータを入れ、2つのコンシューマスレッドがキューからデータを取り出して処理します。
import queue
import threading
def producer(q, items):
for item in items:
q.put(item)
print("Produced:", item)
q.put(None) # 終了を示すためにNoneを追加
def consumer(q):
while True:
item = q.get()
if item is None:
break # 終了を示すNoneを取得したらループを終了
print("Consumed:", item)
q = queue.Queue() # スレッドセーフなキューオブジェクトの作成
# データを生産するスレッド
producer_thread = threading.Thread(target=producer, args=(q, [1, 2, 3, 4, 5]))
producer_thread.start()
# データを消費するスレッド
consumer_thread = threading.Thread(target=consumer, args=(q,))
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
このコードを実行すると、プロデューサーが生産したデータが、コンシューマによって消費される様子を見ることができます。
まとめ
当記事では、PythonのQueueモジュールとその用途について学習してきました。
- そもそもQueueとはなにか?
- Pythonでのqueueモジュールの使い方
- Queueクラスの書き方
この知識を活用することで、あなたのPythonプログラムのデータ管理がより効率的になるでしょう。