In diesem Artikel werden einige Erfahrungen und Erkenntnisse zum gewaltsamen Beenden von Python-Threads mit Ihnen geteilt. Wenn Sie zum Beenden von Threads Gewalt anwenden, besteht eine hohe Wahrscheinlichkeit, dass unerwartete Fehler auftreten. Bitte beachten Sie, dass die Sperrressource nicht freigegeben wird, da der Thread beendet wird!
Vorwort:
Versuchen Sie nicht, einen Python-Thread mit Gewalt zu beenden. Dies ist im Hinblick auf das Service-Design unvernünftig. Multithreading wird für die kollaborative Parallelität von Aufgaben verwendet. Wenn Sie Threads gewaltsam beenden, besteht eine hohe Wahrscheinlichkeit unerwarteter Fehler. Bitte beachten Sie, dass die Sperrressource nicht freigegeben wird, da der Thread beendet wird!
Wir können zwei gängige Beispiele nennen:
1. Thread A hat die Sperre erhalten, weil er gewaltsam beendet wurde und die Sperrressource nicht rechtzeitig mit release() freigegeben wurde, dann werden es alle Threads sein beim Erwerb von Ressourcen blockiert, was ein typisches Deadlock-Szenario darstellt.
2. In einem üblichen Produktions-Konsumenten-Szenario ruft der Konsument Aufgaben aus der Aufgabenwarteschlange ab, wirft die laufende Aufgabe jedoch nicht zurück in die Warteschlange, nachdem sie beendet wurde, was zu Datenverlust führt.
Die folgenden Methoden zum Beenden von Threads in Java und Python:
Java verfügt über drei Methoden zum Beenden von Threads:
1 Exit-Flag, sodass der Thread normal beendet wird, dh der Thread wird beendet, wenn die Ausführungsmethode abgeschlossen ist.
2. Verwenden Sie die Stop-Methode, um den Thread zwangsweise zu beenden (nicht empfohlen, da Stop dasselbe ist wie Anhalten und Fortsetzen und unvorhersehbare Ergebnisse auftreten können).
3. Verwenden Sie die Interrupt-Methode, um den Thread zu unterbrechen.
Python kann zwei Methoden haben:
1. Exit-Markierung
2. Verwenden Sie ctypes, um den Thread gewaltsam zu beenden
Nein Angelegenheit In einer Python- oder Java-Umgebung besteht die ideale Möglichkeit, einen Thread zu stoppen und zu beenden, darin, den Thread Selbstmord begehen zu lassen. Der sogenannte Thread-Selbstmord bedeutet, dass Sie ihm ein Flag geben und er den Thread verlässt.
Im Folgenden werden wir verschiedene Methoden verwenden, um die abnormale Situation beim Stoppen des Python-Threads zu testen. Wir betrachten alle Ausführungsthreads eines Prozesses. Der Prozess verwendet Steuerressourcen und der Thread wird als Planungseinheit verwendet der Prozess.
ps -mp 31449 -o THREAD,tid USER %CPU PRI SCNT WCHAN USER SYSTEM TID root 0.0 - - - - - - root 0.0 19 - poll_s - - 31449 root 0.0 19 - poll_s - - 31450
Nachdem wir alle Threads des Prozesses erhalten haben, wissen wir durch Strace, dass 31450 die Thread-ID ist, die beendet werden muss. Wenn wir töten, stürzt der gesamte Prozess ab. In einer Multithread-Umgebung wird das generierte Signal an den gesamten Prozess übermittelt. Im Allgemeinen haben alle Threads die Möglichkeit, dieses Signal zu empfangen. Der Prozess führt die Signalverarbeitungsfunktion im Thread-Kontext aus, der das Signal empfängt Signal. Es ist schwierig zu wissen, welcher Thread ausgeführt wird. Mit anderen Worten: Das Signal wird zufällig an einen Thread des Prozesses gesendet.
strace -p <span style="font-size:14px;line-height:21px;">31450</span> Process <span style="font-size:14px;line-height:21px;">31450</span> attached - interrupt to quit select(0, NULL, NULL, NULL, {0, 320326}) = 0 (Timeout) select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout) select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout) select(0, NULL, NULL, NULL, {1, 0}) = ? ERESTARTNOHAND (To be restarted) --- SIGTERM (Terminated) @ 0 (0) --- Process <span style="font-size:14px;line-height:21px;">31450</span> detached
Rückruffunktion verhindern, dass der gesamte Prozess beendet wird. Mit anderen Worten: Die Signalfunktion kann nicht erkennen, welchen Thread Sie beenden möchten , es kann einen Thread nicht genau beenden. Obwohl Sie das Signal an die Thread-ID 31450 senden, ist der Signalakzeptor einer der Prozesse, zu denen es gehört. Darüber hinaus sind die an die Signalverarbeitungsfunktion übergebenen Parameter nur die Anzahl der Signale und die Signalstapel, die optional sind. Nach dem Hinzufügen der Signalverarbeitung wird der Prozess nicht beendet
Wenn Sie einen Thread durch externe Benachrichtigung beenden möchten, können Sie einen RPC-Dienst erstellen und verwenden oder auf andere Weise kommunizieren. Signal Signale können das nicht, weil sie nicht mehr Informationen übermitteln können.select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout) select(0, NULL, NULL, NULL, {1, 0}) = ? ERESTARTNOHAND (To be restarted) --- SIGTERM (Terminated) @ 0 (0) --- rt_sigreturn(0xffffffff) = -1 EINTR (Interrupted system call) select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout) select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
Python-Threads werden nicht simuliert, sondern sind echte Kernel-Threads. Der Kernel ruft die Pthread-Methode auf, aber die obere Schicht von Python bietet keine Methode zum Schließen des Threads, daher müssen wir sie selbst verstehen. Es wird dringend empfohlen, die Ereignis- oder benutzerdefinierte Flag-Bit-Methode zu verwenden. Wenn Sie den Thread zwangsweise beenden müssen, können Sie die Python-ctypes-Methode PyThreadState
SetAsyncExc verwenden, um das Beenden zu erzwingen, was keine Auswirkungen auf die laufende Python hat Service.
Das Implementierungsprinzip dieser Funktion ist relativ einfach. Tatsächlich besteht es darin, ein Flag in der virtuellen Python-Maschine zu setzen, und dann führt die virtuelle Maschine eine Ausnahme aus, um den Thread abzubrechen Die Maschine hilft Ihnen beim Ausprobieren des
. Denken Sie daran, einen Thread in Python nicht extern zu beenden. Obwohl Sie die Thread-ID über ctypes finden können, wird durch das direkte Beenden der gesamte Prozess beendet. Der folgende Code ist ein Beispiel für die Verwendung von ctypes zum Beenden eines Threads. Er wird nicht empfohlen, da er zu unhöflich ist.
Schauen wir uns kurz den PyThreadState-Quellcode an , die Ausnahme, die das Thread-Modell auslöst. Interessierte können das Design von Python pystate.c lesen und mit einigenimport ctypes def terminate_thread(thread): if not thread.isAlive(): return exc = ctypes.py_object(SystemExit) res = ctypes.pythonapi.PyThreadState_SetAsyncExc( ctypes.c_long(thread.ident), exc) if res == 0: raise ValueError("nonexistent thread id") elif res > 1: ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None) raise SystemError("PyThreadState_SetAsyncExc failed")
auf YouTube teilen. 原生posix pthread 可以使用 ptread_cancel(tid) 在主线程中结束子线程。但是 Python 的线程库不支持这样做,理由是我们不应该强制地结束一个线程,这样会带来很多隐患,应该让该线程自己结束自己。所以在 Python 中,推荐的方法是在子线程中循环判断一个标志位,在主线程中改变该标志位,子线程读到标志位改变,就结束自己。 类似这个逻辑: 简单的总结,虽然我们可以用ctypes里的pystats来控制线程,但这种粗暴中断线程的方法是不合理的。 请选用 自杀模式 !如果你的线程正在发生io阻塞,而不能判断事件怎么办? 你的程序需要做优化了,最少在网络io层需要有主动的timeout,避免一直的阻塞下去。 【相关推荐】 1. Python免费视频教程 2. Python基础入门教程 Das obige ist der detaillierte Inhalt vonEinführung in Methoden zur nicht erzwungenen Beendigung von Python-Threads. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website! int
PyThreadState_SetAsyncExc(long id, PyObject *exc) {
PyInterpreterState *interp = GET_INTERP_STATE();
...
HEAD_LOCK();
for (p = interp->tstate_head; p != NULL; p = p->next) {
if (p->thread_id == id) {
从链表里找到线程的id,避免死锁,我们需要释放head_mutex。
PyObject *old_exc = p->async_exc;
Py_XINCREF(exc); #增加该对象的引用数
p->async_exc = exc; # 更为exc模式
HEAD_UNLOCK();
Py_XDECREF(old_exc); # 因为要取消,当然也就递减引用
...
return 1; #销毁线程成功
}
}
HEAD_UNLOCK();
return 0;
}
def consumer_threading():
t1_stop= threading.Event()
t1 = threading.Thread(target=thread1, args=(1, t1_stop))
t2_stop = threading.Event()
t2 = threading.Thread(target=thread2, args=(2, t2_stop))
time.sleep(duration)
#stop the thread2
t2_stop.set()
def thread1(arg1, stop_event):
while(not stop_event.is_set()):
#similar to time.sleep()
stop_event.wait(time)
pass
def thread2(arg1, stop_event):
while(not stop_event.is_set()):
stop_event.wait(time)
pass