Heim >Backend-Entwicklung >Golang >In Go geschriebene Python-Erweiterung ignoriert Strg+C
php-Editor Apple hat festgestellt, dass in Go geschriebene Python-Erweiterungen möglicherweise Probleme bei der Verarbeitung des Strg+C-Signals haben. Wenn wir in der Befehlszeile Strg+C drücken, wird normalerweise ein SIGINT-Signal an das laufende Programm gesendet, um es aufzufordern, die Ausführung zu stoppen. Allerdings scheinen in Go geschriebene Python-Erweiterungen dieses Signal zu ignorieren, was dazu führt, dass das Programm nicht ordnungsgemäß beendet wird. Dieses Problem stellt eine potenzielle versteckte Gefahr für Entwickler dar, die Python-Erweiterungen mit Go schreiben, und erfordert besondere Aufmerksamkeit. Daher sollten wir während des Entwicklungsprozesses nach Lösungen suchen, um dieses Problem zu lösen und den normalen Abschluss des Programms sicherzustellen.
Ich verwende einen in go geschriebenen Python-Treiber, der eine Verbindung zu einem Dienst herstellt und einige Verarbeitungsvorgänge durchführt. Wir haben ein Problem mit einer „ungesunden“ Instanz des Dienstes entdeckt, das dazu führte, dass der Treiber hängen blieb und nicht beendet werden konnte, es sei denn, wir kill
den Prozess.
Bei einigen Experimenten habe ich festgestellt, dass das Programm beim Ausführen einer in go geschriebenen Erweiterung das ausgegebene ignoriert ctrl+c
命令,直到控制权返回到 python,而使用 c 编写的扩展则不会发生这种情况,其中在执行时引发 keyboardinterrupt
c代码。我的问题是为什么会发生这种情况以及是否有办法规避这个问题或发出某种超时。尝试使用 threading.timer
引发异常来模拟超时,但问题是该异常是在它自己的线程中引发的,并且不会中断主线程。在python(cpython)3.9
和3.10
中测试。至于我写的poc扩展,go版本是1.20.4
,c编译器是9.4.0
.
Ich werde unten einen kleinen Hinweis hinterlassen.
Python-Code:
import ctypes import ctypes go_library = ctypes.cdll.loadlibrary('./go_library.so') hello_go = go_library.helloworld c_library = ctypes.cdll.loadlibrary("./c_library.so") hello_c = c_library.helloworld try: print("calling golang code") hello_go() print("calling c code") hello_c() except keyboardinterrupt: print("ctrl+c issued dd:") finally: print("done")
Go-Erweiterung
package main import ( "c" "log" "time" ) func helloworld(){ log.println("hello world") time.sleep(10 * time.second) log.println("done sleeping") } func main(){ }
c-Erweiterung
#include <stdio.h> int helloWorld() { printf("Hello from C\n"); sleep(10); printf("Done sleeping from C\n"); return 0; }
Ich bin auch auf die gleiche Situation gestoßen. Nach einiger Recherche habe ich die Lösung gefunden.
Basierend auf dieser Antwort:
Python installiert einen Signalhandler auf sigint, der einfach ein Flag setzt, das von der Hauptinterpreterschleife überprüft wird. Damit dieser Handler ordnungsgemäß funktioniert, muss der Python-Interpreter den Python-Code ausführen.
Es scheint, dass Golang beim Ausführen von Golang-Code den in Python installierten Signint-Signal-Handler aufruft, um das Flag zu setzen. Daher wird beim Zurücklaufen auf Python ein Tastaturinterrupt erkannt.
Aus der golang-Dokumentation:
(wenn ein Non-Go-Programm Go-Code aufruft) Wenn notify für ein asynchrones Signal aufgerufen wird, wird ein Go-Signalhandler für das Signal installiert. Wenn später für das Signal „Reset“ aufgerufen wird, wird die ursprüngliche Verarbeitung des Signals wiederhergestellt und der Nicht-Go-Signalhandler (falls vorhanden) wiederhergestellt.
Der folgende Code erfasst also die Signatur im Go-Code und gibt die Funktion zurück, sobald die Signatur auftritt.
func helloWorld() { c := make(chan os.Signal) signal.Notify(c, syscall.SIGINT) // the original handling for that signal will be reinstalled, restoring the non-Go signal handler if any. defer signal.Reset(syscall.SIGINT) go func() { log.Println("Hello World") time.Sleep(10 * time.Second) log.Println("Done sleeping") c <- nil }() // wait go routine to finish or signal received <-c }
Das obige ist der detaillierte Inhalt vonIn Go geschriebene Python-Erweiterung ignoriert Strg+C. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!