質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1902閲覧

Pythonの並行処理(threading.Thread)の挙動について

atabo

総合スコア9

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2021/12/02 12:06

現在、並行処理について勉強中なのですが、
queueモジュールのドキュメントに次のようなサンプルコードがあります。

この無限ループが終了する理由がわからないため教えて頂きたいです。

https://docs.python.org/3/library/queue.html

import threading, queue q = queue.Queue() def worker(): while True: item = q.get() print(f'Working on {item}') print(f'Finished {item}') q.task_done() # turn-on the worker thread threading.Thread(target=worker, daemon=True).start() # send thirty task requests to the worker for item in range(30): q.put(item) print('All task requests sent\n', end='') # block until all tasks are done q.join() print('All work completed')

上記では、スレッドは次のようにバックグラウンドで開始しているのだと思っています。

threading.Thread(target=worker, daemon=True).start()

worker()は, while True: で無限ループして、キューが追加されたら処理して、
処理が終わったらq.task_done()で終わったことを通知してを繰り返し、
全部のキューの処理が終わるまでq.join()でブロックして、全部終わったら最後のprint文が表示される・・・

と、ざっくりこういった流れかと思います。

今、ノートブック(jupyter lab)で動かしているのですが、無限ループをバックグラウンドで実行しているのに、
q.join()の後でセルの実行がちゃんと終了することに疑問をもっています。

「なぜ無限ループを回しているはずのスレッドが終了するのか」がよくわかっていません。

どなたかご教示頂けますと幸いです。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

「なぜ無限ループを回しているはずのスレッドが終了するのか」がよくわかっていません。

その「無限ループ」のスレッドが自発的に終了しているわけではなくて、メインのスレッドが終了してプロセス全体が終了してるので、それに引きずられて終了しているということかと。

threadingモジュールのページの"Thread Objects"の項にある"Note"の直前の記述も参考にどうぞ。

投稿2021/12/02 13:31

angel_p_57

総合スコア1672

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

atabo

2021/12/03 02:00

ご回答ありがとうございました! 今回はノートブックで実行してのでカーネルを停止するまでスレッドは残ってしまうようでしたが、 もしこれをpythonファイルで実行した場合は、angel_p_57さんのご指摘のように 最後はデーモンのスレッドだけが残るので デーモンのスレッド含めpythonプログラム全体が終了されることになるのだろうと思っています。 大変参考になりました、ありがとうございました!
guest

0

日本語の方のマニュアル

Queue.join()
キューにあるすべてのアイテムが取り出されて処理されるまでブロックします。

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

に書かれているように、「未完了タスクカウントが0になった」が起こったからです。

投稿2021/12/02 12:55

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

「なぜ無限ループを回しているはずのスレッドが終了するのか」がよくわかっていません。

スレッドは終了していません。
「無限ループを回しているはずのスレッドが終了する」という認識の方が誤りです。
スレッドは無限ループの中、q.get()ブロックされた状態で残っています。
ノートブックであれば、カーネルを停止するまでそのままです。


別のセルに

python

1print(threading.active_count())

を入れて確認してみてください。
質問のコードを実行した回数分、生存中の Thread オブジェクトの数が増えていくことがわかると思います。

また、例えば、スレッドの処理の中のget()を

python

1item = q.get(timeout=30)

に変えて何度も実行したあと30秒待てば、スレッドがEmpty例外で終了していくことと、threading.active_count()の値が減ることも確認できるでしょう。

投稿2021/12/02 14:57

編集2021/12/02 15:08
quickquip

総合スコア11072

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

atabo

2021/12/03 01:57

ご回答ありがとうございます!おっしゃるようにスレッド数が表示されスレッドが残っており、 q.put(99)のようにキューに追加すると再度実行されることも確認できました。 ノートブックの場合はカーネルのプロセスがずっと残っており、 (ちゃんと理解できてないですが恐らく今回のデーモン以外のスレッドも何かしら残っており)、 今回のスレッドも残り続けていると理解しました。 もしこれをpythonファイルで実行した場合は、 先のangel_p_57さんのご回答のように最後はデーモンのスレッドだけが残るので デーモンのスレッド含めpythonプログラム全体が終了されるのだとも理解しました。 大変勉強になりました、ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問