Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonのマルチスレッド処理におけるキューと優先度付きキューの使い方

Queueモジュールとは

Pythonのqueueモジュールを使うと、複数のスレッド間で安全にデータをやり取りできるキューを作成できます。キューは最大で指定した数のアイテムを保持でき、スレッドセーフな設計になっているため、マルチスレッドプログラミングでもデータ競合を気にせず利用できます。

キューを操作するための主なメソッドは以下の通りです。

  • get() − キューからアイテムを取り出して返します。
  • put() − キューにアイテムを追加します。
  • qsize() − 現在キューに入っているアイテムの数を返します。
  • empty() − キューが空の場合はTrue、そうでなければFalseを返します。
  • full() − キューが満杯の場合はTrue、そうでなければFalseを返します。

サンプルコード

以下は、3つのワーカースレッドが1つのキューからデータを取り出して処理する例です(Python 3系の記法)。

#!/usr/bin/python3
import queue
import threading
import time

exitFlag = 0

class myThread(threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q

    def run(self):
        print("Starting " + self.name)
        process_data(self.name, self.q)
        print("Exiting " + self.name)

def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print("%s processing %s" % (threadName, data))
        else:
            queueLock.release()
        time.sleep(1)

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1

# 新しいスレッドを作成
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

# キューにデータを投入
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()

# キューが空になるまで待機
while not workQueue.empty():
    pass

# スレッドに終了を通知
exitFlag = 1

# すべてのスレッドの完了を待機
for t in threads:
    t.join()

print("Exiting Main Thread")

実行結果

上記のコードを実行すると、次のような結果が出力されます。

Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread

コードの解説

このプログラムの処理の流れは以下の通りです。

  1. スレッドの作成myThreadクラスをもとに3つのワーカースレッドを生成し、開始します。
  2. キューへの投入: メインスレッドがロックを取得し、「One」〜「Five」の5つのデータをキューに追加します。
  3. データ処理: 各ワーカースレッドはロックを取得しながらキューからデータを取り出し、処理を行います。
  4. 終了処理: キューが空になったらexitFlagを立ててスレッドに終了を通知し、join()ですべてのスレッドの完了を待ちます。

優先度付きキュー(PriorityQueue)について

優先キューを実現したい場合は、queue.PriorityQueueを使用します。通常のQueueがFIFO(先入れ先出し)方式であるのに対し、PriorityQueueは優先度の高いアイテムから順に取り出されます。優先度はタプルの最初の要素で指定するのが一般的です。

import queue

pq = queue.PriorityQueue()
pq.put((2, "低優先度のタスク"))
pq.put((1, "高優先度のタスク"))
pq.put((3, "最低優先度のタスク"))

while not pq.empty():
    print(pq.get()[1])

# 出力順: 高優先度のタスク → 低優先度のタスク → 最低優先度のタスク

このように、queueモジュールを活用することで、マルチスレッド環境でも安全かつ柔軟にタスク管理を行うことができます。

  1. C/C++で学ぶ優先度付きキュー(プライオリティキュー)の基本と実装

    優先度付きキュー(プライオリティキュー)とは、要素に割り当てられた「優先度」に従って挿入・削除が行われる特殊なキューの一種です。優先度は0〜10の整数値で表現され、0が最も高い優先度、10が最も低い優先度を意味します。病院の救急外来で重症患者が待ち順序に関係なく先に診察されるように、重要度の高いタスクを優先的に処理したい場面で活躍するデータ構造です。 優先度付きキューを守る2つの基本ルール 優先度付きキューを実装する際には、次の2つのルールに従います。 優先度の高い要素ほど先に処理される — 最も優先度の高いデータは、優先度の低いデータよりも先に実行されます。 同じ優先度なら追加順に処理さ

  2. C言語で連結リストを使った優先度付きキューの実装方法

    本記事では、整数値の「データ」と「優先度」が与えられたとき、指定された優先度に従って連結リスト(リンクリスト)を構築し、結果を表示する方法を解説します。 優先度付きキューとは キューはFIFO(First In, First Out:先入れ先出し)方式のデータ構造であり、最初に挿入された要素が最初に取り除かれます。 一方、優先度付きキュー(プライオリティキュー)は、要素の挿入・削除を「優先度」に基づいて行えるキューの一種です。キュー、スタック、連結リストなどのデータ構造を用いて実装でき、以下のルールに従って動作します。 優先度が最も高いデータ(要素)は、優先度が低いものよりも先に処理される。