この記事では、Python スレッドでの配置と破棄について詳しく説明します (例とともに)。一定の参考価値があります。困っている友人は参照できます。お役に立てれば幸いです。
仕事が始まる前に何かがおかしいと感じ、自分が責任を負わされるような気がしました。いや、罪悪感を感じるのは勤務3日目です。
モジュールを動的にロードしてスレッドで実行できる素晴らしいバックグラウンド プログラムがあり、これによりプラグインの機能を実現できます。モジュールが更新されると、バックグラウンド プログラム自体は終了せず、モジュールに対応するスレッドを閉じ、コードを更新してから開始するだけです。6 は不可能です。
そこで、自分のスキルを披露するためにモジュールを作成しましたが、exit 関数を書き忘れたため、モジュールが更新されるたびに新しいスレッドが作成されてしまいました。プログラムを再起動しない限り、それらのスレッドは生き続けてください。
これは不可能です。掃除する方法を見つけなければなりません。そうしないと爆発してしまうのではないかと心配です。
それでは、どうやって掃除すればいいのでしょうか?私が思いつくのは 2 つのステップだけです:
クリーンアップする必要があるスレッド番号を見つけます;
それらを破棄します;
通常のトラブルシューティングと同様に、まず ps コマンドで対象プロセスのスレッド状態を確認します。 setName、通常は対応するスレッドを参照する必要があります。次のコードを直接使用して、このスレッドをシミュレートします。
マルチスレッドの Python バージョン
#coding: utf8 import threading import os import time def tt(): info = threading.currentThread() while True: print 'pid: ', os.getpid() print info.name, info.ident time.sleep(3) t1 = threading.Thread(target=tt) t1.setName('OOOOOPPPPP') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('EEEEEEEEE') t2.setDaemon(True) t2.start() t1.join() t2.join()
出力:
root@10-46-33-56:~# python t.py pid: 5613 OOOOOPPPPP 139693508122368 pid: 5613 EEEEEEEEE 139693497632512 ...
Python で出力されたスレッド名が何であるかを確認できます。私たちはそれを設定しましたが、Ps の結果は私に人生を疑わせました:
root@10-46-33-56:~# ps -Tp 5613 PID SPID TTY TIME CMD 5613 5613 pts/2 00:00:00 python 5613 5614 pts/2 00:00:00 python 5613 5615 pts/2 00:00:00 python
通常はこんなはずではありません。少し混乱しています。ずっと間違って覚えていたのでしょうか?別の言語バージョンのマルチスレッドを使用してテストします:
C バージョンのマルチスレッド
#include<stdio.h> #include<sys> #include<sys> #include<pthread.h> void *test(void *name) { pid_t pid, tid; pid = getpid(); tid = syscall(__NR_gettid); char *tname = (char *)name; // 设置线程名字 prctl(PR_SET_NAME, tname); while(1) { printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname); sleep(3); } } int main() { pthread_t t1, t2; void *ret; pthread_create(&t1, NULL, test, (void *)"Love_test_1"); pthread_create(&t2, NULL, test, (void *)"Love_test_2"); pthread_join(t1, &ret); pthread_join(t2, &ret); }</pthread.h></sys></sys></stdio.h>
出力:
root@10-46-33-56:~# gcc t.c -lpthread && ./a.out pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 ...
PS コマンドを使用して再度確認します:
root@10-46-33-56:~# ps -Tp 5575 PID SPID TTY TIME CMD 5575 5575 pts/2 00:00:00 a.out 5575 5576 pts/2 00:00:00 Love_test_1 5575 5577 pts/2 00:00:00 Love_test_2
これは正解です。確かに Ps を通してスレッド名が表示されます。
しかし、Python のものが表示されないのはなぜでしょうか?スレッド名は setName
を通じて設定されるため、定義を見てみましょう:
[threading.py] class Thread(_Verbose): ... @property def name(self): """A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor. """ assert self.__initialized, "Thread.__init__() not called" return self.__name @name.setter def name(self, name): assert self.__initialized, "Thread.__init__() not called" self.__name = str(name) def setName(self, name): self.name = name ...
ここで見ているのは、実際には Thread
オブジェクトのプロパティを設定しているだけです。ルートに触れていない場合は、非表示になるはずです~
ps
または /proc/
を外部に使用することはできなくなったようです Python スレッド名前が検索されるため、Python 内でのみ解決できます。
そこで問題は、Python 内で実行中のすべてのスレッドを取得する方法です。
threading.enumerate
はこの問題を完全に解決できます。なぜですか?
次の関数のドキュメントに明確に記載されているため、終了したものと開始されていないものを除く、すべてのアクティブな スレッド オブジェクト が返されます。
[threading.py] def enumerate(): """Return a list of all Thread objects currently alive. The list includes daemonic threads, dummy thread objects created by current_thread(), and the main thread. It excludes terminated threads and threads that have not yet been started. """ with _active_limbo_lock: return _active.values() + _limbo.values()
Thread オブジェクトを取得しているので、これを通じてスレッドに関連する情報を取得できます。
完全なコード例を参照してください:
#coding: utf8 import threading import os import time def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident print time.sleep(1) def tt(): info = threading.currentThread() pid = os.getpid() while True: print 'pid: {}, tid: {}, tname: {}'.format(pid, info.name, info.ident) time.sleep(3) return t1 = threading.Thread(target=tt) t1.setName('Thread-test1') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('Thread-test2') t2.setDaemon(True) t2.start() t3 = threading.Thread(target=get_thread) t3.setName('Checker') t3.setDaemon(True) t3.start() t1.join() t2.join() t3.join()
出力:
root@10-46-33-56:~# python t_show.py pid: 6258, tid: Thread-test1, tname: 139907597162240 pid: 6258, tid: Thread-test2, tname: 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Checker 139907576182528 ...
コードは少し長く見えますが、ロジックは非常に単純です。Thread-test1
および Thread-test2
は、現在の PID、スレッド ID、およびスレッド名を出力し、3 秒後に終了します。これは、スレッドの通常の終了をシミュレートするためです。
Checker
スレッドは、threading.enumerate
を通じて現在のプロセス内のすべてのアクティブなスレッドを毎秒出力します。
最初に Thread-test1
と Thread-test2
の情報が表示されており、終了後は だけが表示されていることがわかります。 MainThread
と Checker
は、それ自体です。
名前とスレッドIDが取得できるので、指定したスレッドを強制終了することもできます。
ここで、Thread-test2
が黒くなり、おかしくなり、それを停止する必要があるとします。その場合、次の方法で解決できます。
上記のコードでは基本的には、次のコードを追加して追加します。
def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") def stop_thread(thread): _async_raise(thread.ident, SystemExit) def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident, t.is_alive() if t.name == 'Thread-test2': print 'I am go dying! Please take care of yourself and drink more hot water!' stop_thread(t) print time.sleep(1)
Output
root@10-46-33-56:~# python t_show.py pid: 6362, tid: 139901682108160, tname: Thread-test1 pid: 6362, tid: 139901671618304, tname: Thread-test2 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! pid: 6362, tid: 139901682108160, tname: Thread-test1 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True // Thread-test2 已经不在了
しばらくすると、Thread-test2
をこのように扱いますが、それでも引き続き考慮されます :もっと熱いお湯を飲みましょう,
追伸: 熱いお湯も良いですが、8杯で十分なので、欲張らないでください。
本題に戻りますが、上記の方法は非常に大雑把ですが、なぜそう言えるのでしょうか?
その原理は、Python の組み込み API を使用して指定されたスレッドで例外をトリガーし、スレッドが自動的に終了できるようにするためです。 # #この方法は最後の手段として使用しないでください。一定の確率で、言いようのない問題が発生する可能性があります。覚えて!なぜ知っているのかは聞かないでください...
スレッドを停止するのはなぜそれほど難しいのですかマルチスレッド自体は、プロセス下で協調的に同時実行できるように設計されています。スケジューリングとスレッドがプロセス リソースを共有するため、多くのロック メカニズムと状態制御が存在します。
強制的にスレッドを強制終了すると、予期せぬバグが発生する可能性が高くなります。また、最も重要なロック リソースの解放によって、予期しない問題が発生する可能性もあります。kill はプロセスを処理することによってのみ期待を達成できるため、シグナルを通じてプロセスを強制終了するのと同じように、スレッドを直接強制終了することもできませんが、スレッドを処理することは明らかに不可能です。殺されると、プロセス全体が終了します。
そして、GIL のせいで、多くの子供たちは、Python のスレッドは Python 自体によって実装されており、実際には存在しないと考えています。Python は直接破棄されるべきですよね?
しかし、実際には、Python のスレッドは本物のスレッドです。 ######それはどういう意味ですか? Python スレッドは、pthread を通じてオペレーティング システムによって作成されるネイティブ スレッドです。 Python は、GIL を使用してこれらのスレッドを制約し、いつスケジュールを開始するかを決定するだけです。たとえば、多数の命令を実行した後、GIL を引き渡します。花魁が誰に勝つかについては、オペレーティング システムによって異なります。
これが単純なスレッドの場合、システムには実際には、
pthread_exit、pthread_kill
、pthread_cancel
などのスレッドを終了する方法があります。詳細については、https://www.cnblogs.com/Creat... を参照してください。残念なことに、これらのメソッドは Python レベルでカプセル化されていません。なんてことだ、とても怒っている!糸は優しく扱うべきだと思われているのかもしれません。
スレッドを穏やかに終了する方法
実行後に終了するか、フラグ ビットを設定して、フラグ ビットを頻繁に確認してください。終了する必要がある場合は、終了してください。
拡張機能
転載にご注意ください出典: https://segmentfault.com/a/11...
c
linux8
背景仕事を始める前に何かがおかしいと感じ、自分が責任を負わされるような気がしました。いや、罪悪感を感じるのは勤務3日目です。 モジュールを動的にロードしてスレッドで実行できる素晴らしいバックグラウンド プログラムがあり、これによりプラグインの機能を実現できます。モジュールが更新されると、バックグラウンド プログラム自体は終了せず、モジュールに対応するスレッドを閉じ、コードを更新してから開始するだけです。6 は不可能です。
そこで、自分のスキルを披露するためにモジュールを作成しましたが、exit 関数を書き忘れたため、モジュールが更新されるたびに新しいスレッドが作成されてしまいました。プログラムを再起動しない限り、それらのスレッドは生き続けてください。 これは不可能です。掃除する方法を見つけなければなりません。そうしないと爆発してしまうのではないかと心配です。 それでは、どうやって掃除すればいいのでしょうか?私が思いつくのは 2 つのステップだけです: クリーンアップする必要があるスレッド番号を見つけます; それらを破棄します; スレッド ID を確認する#coding: utf8 import threading import os import time def tt(): info = threading.currentThread() while True: print 'pid: ', os.getpid() print info.name, info.ident time.sleep(3) t1 = threading.Thread(target=tt) t1.setName('OOOOOPPPPP') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('EEEEEEEEE') t2.setDaemon(True) t2.start() t1.join() t2.join()
root@10-46-33-56:~# python t.py pid: 5613 OOOOOPPPPP 139693508122368 pid: 5613 EEEEEEEEE 139693497632512 ...
root@10-46-33-56:~# ps -Tp 5613 PID SPID TTY TIME CMD 5613 5613 pts/2 00:00:00 python 5613 5614 pts/2 00:00:00 python 5613 5615 pts/2 00:00:00 python
#include<stdio.h> #include<sys> #include<sys> #include<pthread.h> void *test(void *name) { pid_t pid, tid; pid = getpid(); tid = syscall(__NR_gettid); char *tname = (char *)name; // 设置线程名字 prctl(PR_SET_NAME, tname); while(1) { printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname); sleep(3); } } int main() { pthread_t t1, t2; void *ret; pthread_create(&t1, NULL, test, (void *)"Love_test_1"); pthread_create(&t2, NULL, test, (void *)"Love_test_2"); pthread_join(t1, &ret); pthread_join(t2, &ret); }</pthread.h></sys></sys></stdio.h>
root@10-46-33-56:~# gcc t.c -lpthread && ./a.out pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 pid: 5575, thread_id: 5577, t_name: Love_test_2 pid: 5575, thread_id: 5576, t_name: Love_test_1 ...
root@10-46-33-56:~# ps -Tp 5575 PID SPID TTY TIME CMD 5575 5575 pts/2 00:00:00 a.out 5575 5576 pts/2 00:00:00 Love_test_1 5575 5577 pts/2 00:00:00 Love_test_2
setName
を通じて設定されるため、定義を見てみましょう:[threading.py] class Thread(_Verbose): ... @property def name(self): """A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor. """ assert self.__initialized, "Thread.__init__() not called" return self.__name @name.setter def name(self, name): assert self.__initialized, "Thread.__init__() not called" self.__name = str(name) def setName(self, name): self.name = name ...
Thread
オブジェクトのプロパティを設定しているだけです。ルートに触れていない場合は、非表示になるはずです~ps
または/proc/ を外部に使用することはできなくなったようです Python スレッド名前が検索されるため、Python 内でのみ解決できます。
threading.enumerate
次の関数のドキュメントに明確に記載されているため、終了したものと開始されていないものを除く、すべてのアクティブな
スレッド オブジェクト が返されます。
[threading.py] def enumerate(): """Return a list of all Thread objects currently alive. The list includes daemonic threads, dummy thread objects created by current_thread(), and the main thread. It excludes terminated threads and threads that have not yet been started. """ with _active_limbo_lock: return _active.values() + _limbo.values()
#coding: utf8 import threading import os import time def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident print time.sleep(1) def tt(): info = threading.currentThread() pid = os.getpid() while True: print 'pid: {}, tid: {}, tname: {}'.format(pid, info.name, info.ident) time.sleep(3) return t1 = threading.Thread(target=tt) t1.setName('Thread-test1') t1.setDaemon(True) t1.start() t2 = threading.Thread(target=tt) t2.setName('Thread-test2') t2.setDaemon(True) t2.start() t3 = threading.Thread(target=get_thread) t3.setName('Checker') t3.setDaemon(True) t3.start() t1.join() t2.join() t3.join()
出力:
root@10-46-33-56:~# python t_show.py pid: 6258, tid: Thread-test1, tname: 139907597162240 pid: 6258, tid: Thread-test2, tname: 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Thread-test1 139907597162240 Checker 139907576182528 Thread-test2 139907586672384 ------- Running threads On Pid: 6258 ------- MainThread 139907616806656 Checker 139907576182528 ...
Thread-test1 および Thread-test2
は、現在の PID、スレッド ID、およびスレッド名を出力し、3 秒後に終了します。これは、スレッドの通常の終了をシミュレートするためです。Checker
スレッドは、threading.enumerate
を通じて現在のプロセス内のすべてのアクティブなスレッドを毎秒出力します。最初に
Thread-test1 と
Thread-test2
だけが表示されていることがわかります。 MainThread と
Checker は、それ自体です。
名前とスレッドIDが取得できるので、指定したスレッドを強制終了することもできます。
ここで、
Thread-test2 が黒くなり、おかしくなり、それを停止する必要があるとします。その場合、次の方法で解決できます。
上記のコードでは基本的には、次のコードを追加して追加します。
def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") def stop_thread(thread): _async_raise(thread.ident, SystemExit) def get_thread(): pid = os.getpid() while True: ts = threading.enumerate() print '------- Running threads On Pid: %d -------' % pid for t in ts: print t.name, t.ident, t.is_alive() if t.name == 'Thread-test2': print 'I am go dying! Please take care of yourself and drink more hot water!' stop_thread(t) print time.sleep(1)
root@10-46-33-56:~# python t_show.py pid: 6362, tid: 139901682108160, tname: Thread-test1 pid: 6362, tid: 139901671618304, tname: Thread-test2 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True Thread-test2 139901671618304 True Thread-test2: I am go dying. Please take care of yourself and drink more hot water! pid: 6362, tid: 139901682108160, tname: Thread-test1 ------- Running threads On Pid: 6362 ------- MainThread 139901706389248 True Thread-test1 139901682108160 True Checker 139901661128448 True // Thread-test2 已经不在了
Thread-test2
をこのように扱いますが、それでも引き続き考慮されます :もっと熱いお湯を飲みましょう,
本題に戻りますが、上記の方法は非常に大雑把ですが、なぜそう言えるのでしょうか?
その原理は、Python の組み込み API を使用して指定されたスレッドで例外をトリガーし、スレッドが自動的に終了できるようにするためです。 # #この方法は最後の手段として使用しないでください。一定の確率で、言いようのない問題が発生する可能性があります。覚えて!なぜ知っているのかは聞かないでください...
スレッドを停止するのはなぜそれほど難しいのですかマルチスレッド自体は、プロセス下で協調的に同時実行できるように設計されています。スケジューリングとスレッドがプロセス リソースを共有するため、多くのロック メカニズムと状態制御が存在します。
強制的にスレッドを強制終了すると、予期せぬバグが発生する可能性が高くなります。また、最も重要なロック リソースの解放によって、予期しない問題が発生する可能性もあります。 kill はプロセスを処理することによってのみ期待を達成できますが、スレッドを処理することは明らかに不可能であるため、シグナルを通じてプロセスを強制終了するのと同じように、スレッドを直接強制終了することさえできません。どのスレッドが強制終了されると、プロセス全体が終了します。 そして、GIL のせいで、多くの子供たちは、Python のスレッドは Python 自体によって実装されており、実際には存在しないと考えています。Python はスレッドを直接破棄できるはずですよね。 しかし、実際には、Python のスレッドは本物のスレッドです。 ######それはどういう意味ですか? Python スレッドは、pthread を通じてオペレーティング システムによって作成されるネイティブ スレッドです。 Python は、GIL を使用してこれらのスレッドを制約し、いつスケジュールを開始するかを決定します。たとえば、多数の命令を実行した後、GIL が引き渡されます。花魁が誰に勝つかについては、オペレーティング システムによって異なります。 これが単純なスレッドの場合、システムには実際には、pthread_exit
、pthread_kill
、pthread_cancel
などのスレッドを終了する方法があります。詳細については、https://www.cnblogs.com/Creat... を参照してください。残念なことに、これらのメソッドは Python レベルでカプセル化されていません。なんてことだ、とても怒っている!糸は優しく扱うべきだと思われているのかもしれません。スレッドを穏やかに終了する方法
スレッドを穏やかに終了したい場合、それはほとんどナンセンスです~
実行後に終了するか、フラグ ビットを設定して、フラグ ビットを頻繁に確認してください。終了する必要がある場合は、終了してください。
無断転載禁止
## #### ########################報告#####################
興味があるかもしれません
##2 コメント
時間の並べ替え
私だったら、-9人を殺すかもしれませんが、1人を手放すよりは誤って1000人を殺したほうがいいです、へへ
###いいぞ### ###返事###
以上がPython スレッドでの配置と破棄の詳細な紹介 (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。