まず、一番最初に言わなければならないことはdel
は変数や配列等の要素の削除であって、オブジェクトの削除ではありません。変数の場合はオブジェクトへのアクセスにその変数が使えなくなるだけ、配列等の要素の削除であれば、要素であったオブジェクトが配列等から除外されるだけであり、オブジェクト自体がなくなるというわけではありません。オブジェクトへの参照が一つ減ることになるため、そのオブジェクトの参照カウントが0になればオブジェクトも同時に削除されますが、他からも参照されていれば、del
によって削除されることはありません。
ここまでは十分わかっていますよね。では、スレッドが実行されているとき、スレッドオブジェクトを参照しているのは本当にその変数だけなのでしょうか?
Python
1import sys
2import threading
3import time
4
5def thread_run():
6 print('therad start')
7 time.sleep(10)
8 print('thread end')
9
10t = threading.Thread(target=thread_run)
11
12print('t ref count: %d' % sys.getrefcount(t))
13t.start()
14print('t ref count: %d' % sys.getrefcount(t))
15time.sleep(20)
16print('t ref count: %d' % sys.getrefcount(t))
sys.getrefcount()
はオブジェクトの参照カウント数を取得する関数です。関数内部でも参照しているため、常に1多いことに注意してください。上記を実行してみればわかりますが、t.start()
を実行後にt
に対する参照カウント数が増えます(Python2では2->10にPython3では2->9に)。そして、スレッドが終わったであろう頃に再度確認すると参照カウント数はもとに戻ります。
詳しいところまで追っていませんが、スレッドがアクティブに実行しているときは、それらスレッドを管理するところでスレッドが参照されているという仕組みのようです。そう言った仕組みでなければ、threading.active_count()
でアクティブなスレッドの数を数えるなどできるはずもありませんので、当たり前と言えば当たり前かも知れません。つまり、スレッドがアクティブであるうちはいくらdel t
等で参照カウント数を一つ減らしても、スレッドオブジェクト自体の参照カウント数は0になることはなく、スレッドが破棄されることは無いと言うことです。
ということで、del
では既に動作しているスレッドは停止もしませんし、破棄もされません。そのまま動き続けます。そして、スレッドが終了すれば、参照もなくなるため、(他に参照しているものがなければ)参照カウント数が0になってオブジェクトが破棄されます。
スレッドを強制的に止めたい場合はどうするかですが、現在の所、Pythonのthreadingの実装では、スレッドを外部から停止する方法はないようです。スレッドがループになっていれば、スレッド外部の変数をフラグにして次のループの実行を止めると言うぐらいが現状のようです。multiprocessingであれば別プロセスなので、プロセスにSIGTERM送るとかの手段はあるようです。調べると色々サンプルがでてきますので、"python thread stop"などのキーワードでググってみてください。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。