Python

Queueモジュールの使い方とThreadingモジュールでマルチスレッドを扱う方法について

By 2021年10月24日No Comments

この記事ではPythonの標準ライブラリであるQueueモジュールの使い方とthreadingモジュールでマルチスレッドを扱う方法について解説します。

Queueモジュールは指定の順番でデータを取り出すことができます。データを取り出すにはデータを先入れ先出しで取得できるFIFOキューや後入れ先出しでデータを取得する事ができるLIFOキューなどがあります。

キューとは基本的なデータ構造の一つになります。データ構造とはデータの集まりをコンピュータで効率よく扱う仕組みのことです。そのデータ構造の一つにキューやスタックと呼ばれるものがあります。

FIFOキューはデータを入れた順番通りにデータを取り出すことができます。途中のデータだけを取り出すという操作はできません。キューにデータを入れることをエンキューと呼ばれます。そして、データを取り出すことをデキューと呼びます。

LIFOキューは後入れ先出しでデータを取得する事でスタックと呼ばれます。スタックにデータを入れた順番とは逆の順番にデータを取り出すことができます。最後に入れたデータを最初に取り出す方法でスタックも途中のデータだけを取り出すという操作はできません。スタックにデータを入れることをプッシュと呼び、データを取り出すことをポップと呼びます。

PythonのQueueモジュールの使い方について

それではPythonのライブラリのqueueモジュールを使っていきます。Pythonのqueueモジュールではスタックとキューを実装するメソッドを使うことができます。

まずはqueueモジュールをインポートします。

import queue

Python2系を使っているのであれば下記ように指定してインポートします。

import Queue

この記事ではPython3系の方法で実装していきます。キューへのデータの挿入は「put」を指定して取り出すには「get」を指定します。

import queue

#FIFOキューの作成
q = queue.Queue()

for i in range(5):
    #キューにデータを追加
    q.put(i)

#キューからデータがなくなるまで取り出しを行う
while not q.empty():
    #キューからデータを取得
    print(q.get())

出力結果:

0
1
2
3
4

データが順番に取り出されているのが分かります。 range( )の数値を一つずつエンキューしています。その後に変数qが空になるまで要素をデキューしています。実行結果に並ぶ順番にデータを取り出しているのでFIFOキューである事が確認できます。

次に、後入れ先出しでデータを取り出すLIFOキューであるスタックを使います。上記のプログラムの「q = queue.Queue( )」を「q = queue.LifoQueue( )」に変更します。

import queue

# LIFOキューの作成
q = queue.LifoQueue()

for i in range(5):
    #キューにデータを追加
    q.put(i)
#キューからデータがなくなるまで取り出しを行う
while not q.empty():
    #キューからデータを取得
    print(q.get())

出力結果:

4
3
2
1
0

データが最後から取り出されているのが分かります。range( )の中にある文字を一つずつプッシュしています。その後に変数qが空になるまで要素をポップしています。実行結果に並ぶデータの値の順番が逆になっているのでLIFOキューが確認できます。

QueueモジュールとThreadingモジュールを使ってマルチスレッドプログラミングする

queueモジュールの扱い方と関連のあるマルチスレッドプログラミングについてです。

基本的なプログラムはシングルスレッドで上から下に向けて順番に一つ一つ処理を終わらせていくのが基本ですが、マルチスレッドドプログラミングの場合は処理を行いながら並列にもう一つの処理を同時に行うことでき処理速度を上げることができます。Pythonのthreadingモジュールを使うとマルチスレッドプログラミングで並列処理をする事ができます。

まずはthreadingモジュールとtimeモジュールをインポートします。

import threading
import time

timeモジュールをインポートしているのは、それぞれの関数の処理速度を調整するために使用しています。

import threading, queue
import time

def thread1(num, q):
    for i in num:
        print("thread1の処理:", i)
        time.sleep(1)
        #キューにデータを追加
        q.put(i)

def thread2(q):
    while True:
        num = q.get()
        num += 10
        print("thread2の処理:", num)
        time.sleep(4)

        #キューのタスク処理が完了したときに呼び出します。
        q.task_done()

q = queue.Queue()
for n in range(2):
    thread = threading.Thread(target=thread2, args=(q,))

    #スレッドを開始する
    thread.start()

num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

thread1(num, q)

#キューのアイテムが消費されるのを待ちます
q.join()

出力結果:

thread1の処理: 1
thread1の処理: 2
thread2の処理: 11
thread1の処理: 3
thread2の処理: 12
thread1の処理: 4
thread1の処理: 5
thread2の処理: 13
thread1の処理: 6
thread2の処理: 14
thread1の処理: 7
thread1の処理: 8
thread1の処理: 9
thread2の処理: 15
thread1の処理: 10
thread2の処理: 16
thread2の処理: 17
thread2の処理: 18
thread2の処理: 19
thread2の処理: 20

thread1( )関数とthread2( )関数を並行処理をする事ができました。このように並列処理をすると処理速度を上げたいような処理がある場合などにマルチスレッドを使い並行処理をすると処理速度を上げる事ができます。

しかし、threadingモジュールを使った並列処理は処理を効率化させることができますが、その分パソコンのCPUに負荷をかけることになるので、あまりに重い並列処理をするとPythonのメモリエラーになる可能性があるので注意が必要です。

まとめ

今回はqueueモジュールでデータの先入れ先出しであるFIFOキューと後入れ先出しでデータを取り出すLIFOキューについて解説しました。そして、queueモジュールとthreadingモジュールを使ってマルチスレッドプログラミングをして並列処理しました。複数の処理で処理速度を上げたいような重い処理がある時に並行処理をします。

以上、Pythonのqueueモジュールとマルチスレッドの使い方についてでした。

Udemyの動画学習でもPythonを勉強しよう!

「平日の夜の勉強会には時間が間に合わなくて参加できない」「通勤時間のわずかな隙間時間を勉強時間にあてたい」「本ではよく分からないところを動画で理解を深めたい」そんなあなたはUdemyの動画学習がお勧めです!

UdemyのPythonおすすめ33講座レビューリスト
HOSL

Author HOSL

More posts by HOSL