PythonスレッドがsetDaemonを設定するのはなぜですか



Why Does Python Thread Set Up Setdaemon



PythonスレッドがsetDaemonを設定するのはなぜですか

スカムフライング 網易ゲームの運用および保守プラットフォーム

スカムフライング



何年もの間深夜にチケットサークルに毒を入れているZhaZhafeiは、NetEaseゲームのシニアオペレーションおよびメンテナンスエンジニアです。彼はコードのパフォーマンスとシステムの原則に非常に興味を持っています。 3人に私の先生が必要です。現在、彼は関連する事業開発の監視を担当しています。

序文

Pythonを使用すると、スレッドの知識を見逃すことはありませんが、スレッドについて話すたびに、誰もが無意識のうちにGILグローバルロックについて話します。



しかし実際には、この決まり文句のトピックに加えて、次のような多くの貴重なことを探求することができます。 setDaemon()

スレッドの使用と問題

マルチスレッドを開始するには、次のようなコードを記述します。

1import time 2import threading 3 4def test(): 5 while True: 6 print threading.currentThread() 7 time.sleep(1) 8 9if __name__ == '__main__': 10 t1 = threading.Thread(target=test) 11 t2 = threading.Thread(target=test) 12 t1.start() 13 t2.start()

出力:



1^C 2 3^C^C^C^C^C^C # ctrl-c Cannot be interrupted many times 4 5^C 6 7 8 9 10... (Two threads compete to print)

スレッド化により、並行性の要件を簡単に達成できますが、大きな問題も発生します。 やめる方法は?

上記のプログラムの実行中に、私はを押してみました ctrl-c 、このプログラムの熱意を妨げることはできません!最後に、私はそれを使用する必要があります 殺します ちょうど終わった。

では、どうすればこの問題を回避できますか?つまり、メインスレッドが終了したときに、子スレッドを自動的に終了するにはどうすればよいでしょうか。

デーモンスレッド

同様の経験を持つベテランドライバーは知っておく必要があります、 setDaemon() スレッドを作成する デーモンスレッド ただそれを取得しないでください:

1import time 2import threading 3 4def test(): 5 while True: 6 print threading.currentThread() 7 time.sleep(1) 8 9if __name__ == '__main__': 10 t1 = threading.Thread(target=test) 11 t1.setDaemon(True) 12 t1.start() 13 14 t2 = threading.Thread(target=test) 15 t2.setDaemon(True) 16 t2.start()


出力:

1python2.7 1.py 2 3 4 (Exit directly)

直接終了しますか?もちろん、メインスレッドが実行を終了したので、それは確かに終わりました。デーモンスレッドが設定されているため、この時点で子スレッドも終了します。

突然のデーモン

したがって、問題は、私たちがC言語を学んでいたとき、次のようにデーモンなしで行うことが可能であるように思われたことです。

1#include 2#include 3#include 4 5void *test(void *args) 6{ 7 while (1) 8 { 9 printf('ThreadID: %d ', syscall(SYS_gettid)) 10 sleep(1) 11 } 12} 13 14int main() 15{ 16 pthread_t t1 17 int ret = pthread_create(&t1, NULL, test, NULL) 18 if (ret != 0) 19 { 20 printf('Thread create failed ') 21 } 22 23 Avoid exiting directly 24 sleep(2) 25 printf('Main run.. ') 26}

出力:

1# gcc -lpthread test_pytha.out & ./a 2ThreadID: 31233 3ThreadID: 31233 4Main run... (Quit without hesitation)

PythonもCで書かれているのに、なぜPythonマルチスレッドを終了する必要があるのですか? setDaemon ???

この問題を解決するために、メインスレッドが終了した瞬間からではないのではないかと心配しています。過去には...

抗静脈

Pythonパーサーが終了すると、 wait_for_thread_shutdown 定期的なクリーンアップを実行しましょう。

1// python2.7/python/pythonrun.c 2 3static void 4wait_for_thread_shutdown(void) 5{ 6#ifdef WITH_THREAD 7 PyObject *result 8 PyThreadState *tstate = PyThreadState_GET() 9 PyObject *threading = PyMapping_GetItemString(tstate->interp->modules, 10 'threading') 11 if (threading == NULL) { 12 /* threading not imported */ 13 PyErr_Clear() 14 return 15 } 16 result = PyObject_CallMethod(threading, '_shutdown', '') 17 if (result == NULL) 18 PyErr_WriteUnraisable(threading) 19 else 20 Py_DECREF(result) 21 Py_DECREF(threading) 22#endif 23}

私たちは見た #ifdef WITH_THREAD この関数がマルチスレッドであるかどうかを推測したかもしれませんが、この関数は異なるロジックを実行します

明らかに、上記のスクリプトはこのスレッドロジックにヒットするため、動的になります スレッドモジュールのインポート 、そして実行 _シャットダウン 関数。

この関数の内容は、スレッドモジュールから確認できます。

1# /usr/lib/python2.7/threading.py 2 3_shutdown = _MainThread()._exitfunc 4 5class _MainThread(Thread): 6 7 def __init__(self): 8 Thread.__init__(self, name='MainThread') 9 self._Thread__started.set() 10 self._set_ident() 11 with _active_limbo_lock: 12 _active[_get_ident()] = self 13 14 def _set_daemon(self): 15 return False 16 17 def _exitfunc(self): 18 self._Thread__stop() 19 t = _pickSomeNonDaemonThread() 20 if t: 21 if __debug__: 22 self._note('%s: waiting for other threads', self) 23 while t: 24 t.join() 25 t = _pickSomeNonDaemonThread() 26 if __debug__: 27 self._note('%s: exiting', self) 28 self._Thread__delete() 29 30def _pickSomeNonDaemonThread(): 31 for t in enumerate(): 32 if not t.daemon and t.is_alive(): 33 return t 34 return None

_シャットダウン 実際、それは _MainThread()._ exitfunc 内容は主に 列挙() 返されたすべての結果、すべてjoin()リサイクル

そして 列挙() それは何ですか?

これも通常使用しますが、これが現在のすべてのプロセスです 基準を満たす Pythonスレッドオブジェクト:

1>>> print threading.enumerate() 2[] 1# /usr/lib/python2.7/threading.py 2 3def enumerate(): 4 '''Return a list of all Thread objects currently alive. 5 6 The list includes daemonic threads, dummy thread objects created by 7 current_thread(), and the main thread. It excludes terminated threads and 8 threads that have not yet been started. 9 10 ''' 11 with _active_limbo_lock: 12 return _active.values() + _limbo.values()

基準を満たしていますか? ? ?条件は何ですか? ?心配しないでください、私に言わせてください:

起源からの生存条件について話す

Pythonのスレッドモデルでは、GIL干渉がありますが、スレッドは実際にはネイティブスレッドです

Pythonは、カプセル化の別のレイヤーを追加するだけです。 t_bootstrap 、次に、このカプセル化レイヤーで実際の処理機能を実行します。

スレッド モジュールでは、同様のことも確認できます。

1# /usr/lib/python2.7/threading.py 2 3class Thread(_Verbose): 4 def start(self): 5 ... omitted 6 with _active_limbo_lock: 7 _limbo[self]=self#Key 8 try: 9 _start_new_thread(self.__bootstrap, ()) 10 except Exception: 11 with _active_limbo_lock: 12 del _limbo[self]# focus 13 raise 14 self.__started.wait() 15 16 def __bootstrap(self): 17 try: 18 self.__bootstrap_inner() 19 except: 20 if self.__daemonic and _sys is None: 21 return 22 raise 23 24 def __bootstrap_inner(self): 25 try: 26 ... omitted 27 with _active_limbo_lock: 28 _active[self.__ident]=self#Key 29 Del _limbo[self] #Key 30 ... omitted

上記の一連のコードでは、 _limbo_active 変更には重要なポイントが記されており、次の定義を取得できます。

1 _limbo: It is the object that called start, but has not had time to _start_new_thread 2 _active: living thread object

だから上記に戻って、 _MainThread()._ exitfunc 実行時に、プロセス全体が存在するかどうかを確認します _limbo + _active オブジェクト、

存在する限り、それは呼び出されます join() 、これが閉塞の原因です。

setDaemonの使用

ブロックは無期限に機能せず、ユーザーがスレッドを強制終了するのを賢く支援する方法ではないので、よりエレガントに行うにはどうすればよいでしょうか。

これは、ユーザーがプロセスを終了するフラグを設定する方法を提供することです。 setDaemon

1class Thread(): 2 ... omitted 3 def setDaemon(self, daemonic): 4 self.daemon = daemonic 5 6 ... omitted 7 8# Actually it was posted above, and I will post it again here 9def _pickSomeNonDaemonThread(): 10 for t in enumerate(): 11 if not t.daemon and t.is_alive(): 12 return t 13 return None

子スレッドである限り、すべてを設定します setDaemon(True) 、その後、メインスレッドが終了する準備ができるとすぐに、すべてが素直に破棄され、オペレーティングシステムによってリサイクルされます。

その前はいつも興味がありました。pthreadにはデーモン属性がありません。なぜPythonはそれを持っているのですか?

結果として、これは実際にはPythonレイヤーでのみ機能します(手動スマイリー)

結論

ただ一つ setDaemon これは、スレッド作成プロセスや管理プロセスなど、重要なコンテンツの多くの探索機会につながる可能性があります。

これらは非常に興味深いコンテンツです。使用に限らず、大胆に探求する必要があります〜

過去に素晴らしい

DoomEmacsの紹介

MongoDBの遅いログ最適化プロセスを覚えておいてください

KSMアプリケーションの実践

S3中国語エンコーディングの問題と修復計画

一般的なリアルタイムのログ分類と統計の実践