8.10. "Queue" --- 同期キュークラス
**********************************

注釈: "Queue" モジュールは、Python 3 では "queue" にリネームされまし
  た。 *2to3* ツールが自動的にソースコードの import を修正します。

**ソースコード:** Lib/Queue.py

======================================================================

"Queue" モジュールは、複数プロデューサ-複数コンシューマ (multi-
producer, multi-consumer) キューを実装します。これは、複数のスレッドの
間で情報を安全に交換しなければならないときのマルチスレッドプログラミン
グで特に有益です。このモジュールの "Queue" クラスは、必要なすべてのロ
ックセマンティクスを実装しています。これはPythonのスレッドサポートの状
況に依存します。 "threading" モジュールを参照してください。

このモジュールでは3種類のキューが実装されています。それらはキューから
取り出されるエントリの順番だけが違います。 FIFOキューでは、最初に追加
されたエントリが最初に取り出されます。 LIFOキューでは、最後に追加され
たエントリが最初に取り出されます(スタックのように振る舞います)。 優先
順位付きキュー(priority queue)では、エントリは("heapq" モジュールを利
用して)ソートされ、 最も低い値のエントリが最初に取り出されます。

"Queue" モジュールは以下のクラスと例外を定義します:

class Queue.Queue(maxsize=0)

   FIFOキューのコンストラクタです。*maxsize* はキューに置くことのでき
   る要素数の上限を設定する整数です。いったんこの大きさに達したら、挿
   入はキューの要素が消費されるまでブロックされます。もし *maxsize* が
   0以下であるならば、キューの大きさは無限です。

class Queue.LifoQueue(maxsize=0)

   LIFOキューのコンストラクタです。*maxsize* はキューに置くことのでき
   る要素数の上限を設定する整数です。いったんこの大きさに達したら、挿
   入はキューの要素が消費されるまでブロックされます。もし *maxsize* が
   0以下であるならば、キューの大きさは無限です。

   バージョン 2.6 で追加.

class Queue.PriorityQueue(maxsize=0)

   優先順位付きキューのコンストラクタです。*maxsize* はキューに置くこ
   とのできる要素数の上限を設定する整数です。いったんこの大きさに達し
   たら、挿入はキューの要素が消費されるまでブロックされます。もし
   *maxsize* が0以下であるならば、キューの大きさは無限です。

   最小の値を持つ要素が最初に検索されます (最小の値を持つ値は、
   "sorted(list(entries))[0]" によって返されるものです)。典型的な要素
   のパターンは、"(priority_number, data)" 形式のタプルです。

   バージョン 2.6 で追加.

exception Queue.Empty

   空な "Queue" オブジェクトで、非ブロックメソッドとして "get()" (また
   は "get_nowait()") が呼ばれたとき、送出される例外です。

exception Queue.Full

   満杯な "Queue" オブジェクトで、非ブロックメソッドとして "put()" (ま
   たは "put_nowait()") が呼ばれたとき、送出される例外です。

参考: "collections.deque" は、ロックなしで "popleft()" や "append()"
  とい ったアトミック操作が可能なキューの実装です。


8.10.1. キューオブジェクト
==========================

キューオブジェクト ("Queue", "LifoQueue", "PriorityQueue") は、以下の
publicメソッドを提供しています。

Queue.qsize()

   キューの近似サイズを返します。ここで、qsize() > 0 は後続の get() が
   ブロックしないことを保証しないこと、また qsize() < maxsize が put()
   がブロックしないことを保証しないことに注意してください。

Queue.empty()

   キューが空の場合は "True" を返し、そうでなければ "False" を返します
   。empty() が "True" を返しても、後続の put() の呼び出しがブロックし
   ないことは保証されません。同様に、empty() が "False" を返しても、後
   続の get() の呼び出しがブロックしないことは保証されません。

Queue.full()

   キューが一杯の場合は "True" を返し、そうでなければ "False" を返しま
   す。full() が "True" を返しても、後続の get() の呼び出しがブロック
   しないことは保証されません。同様に、full() が "False" を返しても、
   後続の put() の呼び出しがブロックしないことは保証されません。

Queue.put(item[, block[, timeout]])

   *item* をキューに入れます。 もしオプション引数 *block* が真で
   *timeout* が "None" (デフォルト) の場合は、必要であればフリースロッ
   トが利用可能になるまでブロックします。 *timeout* が正の数の場合は、
   最大で *timeout* 秒間ブロックし、その時間内に空きスロットが利用可能
   にならなければ、例外 "Full" を送出します。 そうでない場合 (*block*
   が偽) は、空きスロットが直ちに利用できるならば、キューにアイテムを
   置きます。 できないならば、例外 "Full" を送出します (この場合
   *timeout* は無視されます)。

   バージョン 2.3 で追加: *timeout* パラメータが追加されました。

Queue.put_nowait(item)

   "put(item, False)" と等価です。

Queue.get([block[, timeout]])

   キューからアイテムを取り除き、それを返します。 オプション引数
   *block* が真で *timeout* が "None" (デフォルト) の場合は、必要であ
   ればアイテムが取り出せるようになるまでブロックします。 もし
   *timeout* が正の数の場合は、最大で *timeout* 秒間ブロックし、その時
   間内でアイテムが取り出せるようにならなければ、例外 "Empty" を送出し
   ます。 そうでない場合 (*block* が偽) は、直ちにアイテムが取り出せる
   ならば、それを返します。 できないならば、例外 "Empty" を送出します
   (この場合 *timeout* は無視されます)。

   バージョン 2.3 で追加: *timeout* パラメータが追加されました。

Queue.get_nowait()

   "get(False)" と等価です。

キューに入れられたタスクが全てコンシューマスレッドに処理されたかどうか
を追跡するために 2つのメソッドが提供されます。

Queue.task_done()

   過去にキューに入れられたタスクが完了した事を示します。キューのコン
   シューマスレッドに利用されます。タスクの取り出しに使われた、各
   "get()" に対して、それに続く "task_done()" の呼び出しは、取り出した
   タスクに対する処理が完了した事をキューに教えます。

   "join()" がブロックされていた場合、全itemが処理された (キューに
   "put()" された全てのitemに対して "task_done()" が呼び出されたことを
   意味します) 時に復帰します。

   キューにある要素より多く呼び出された場合 "ValueError" が発生します
   。

   バージョン 2.5 で追加.

Queue.join()

   キューの中の全アイテムが処理される間でブロックします。

   キューにitemが追加される度に、未完了タスクカウントが増やされます。
   コンシューマスレッドが "task_done()" を呼び出して、itemを受け取って
   それに対する処理が完了した事を知らせる度に、未完了タスクカウントが
   減らされます。未完了タスクカウントが0になったときに、 "join()"  の
   ブロックが解除されます。

   バージョン 2.5 で追加.

キューに入れたタスクが完了するのを待つ例:

   def worker():
       while True:
           item = q.get()
           do_work(item)
           q.task_done()

   q = Queue()
   for i in range(num_worker_threads):
        t = Thread(target=worker)
        t.daemon = True
        t.start()

   for item in source():
       q.put(item)

   q.join()       # block until all tasks are done
