éditeur php Apple a découvert que les extensions Python écrites en Go peuvent rencontrer des problèmes lors de la gestion du signal Ctrl+C. Normalement, lorsque nous appuyons sur Ctrl+C sur la ligne de commande, un signal SIGINT est envoyé au programme en cours d'exécution pour lui demander d'arrêter l'exécution. Cependant, les extensions Python écrites en Go semblent ignorer ce signal, ce qui empêche le programme de s'arrêter correctement. Ce problème constitue un danger potentiel caché pour les développeurs qui écrivent des extensions Python à l'aide de Go et nécessite une attention particulière. Par conséquent, pendant le processus de développement, nous devons rechercher des solutions pour résoudre ce problème afin d'assurer la sortie normale du programme.
J'utilise un pilote python écrit en go qui se connecte à un service et effectue certains traitements. Nous avons découvert un problème avec une instance « malsaine » du service, qui a bloqué le pilote et l'a empêché de terminer à moins que nous kill
le processus.
En faisant quelques expériences, j'ai découvert que lors de l'exécution d'une extension écrite en go, le programme ignore les ctrl+c
命令,直到控制权返回到 python,而使用 c 编写的扩展则不会发生这种情况,其中在执行时引发 keyboardinterrupt
c代码。我的问题是为什么会发生这种情况以及是否有办法规避这个问题或发出某种超时。尝试使用 threading.timer
引发异常来模拟超时,但问题是该异常是在它自己的线程中引发的,并且不会中断主线程。在python(cpython)3.9
和3.10
中测试。至于我写的poc扩展,go版本是1.20.4
,c编译器是9.4.0
émis.
Je laisse un petit poc ci-dessous.
code python :
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")
aller à l'extension
package main import ( "c" "log" "time" ) func helloworld(){ log.println("hello world") time.sleep(10 * time.second) log.println("done sleeping") } func main(){ }
extension c
#include <stdio.h> int helloWorld() { printf("Hello from C\n"); sleep(10); printf("Done sleeping from C\n"); return 0; }
J'ai également rencontré la même situation. Après quelques recherches, j'ai trouvé la solution.
Basé sur cette réponse :
Python installe un gestionnaire de signal sur sigint qui définit simplement un indicateur qui est vérifié par la boucle d'interprétation principale. Pour que ce gestionnaire fonctionne correctement, l'interpréteur Python doit exécuter le code Python.
Il semble que lors de l'exécution du code golang, golang appelle le gestionnaire de signal sigint installé par python pour définir l'indicateur. Par conséquent, lors du retour à Python, une interruption clavier est détectée.
De la documentation Golang :
(quand un programme non-go appelle le code go) Si notify est appelé pour un signal asynchrone, un gestionnaire de signal go est installé pour le signal. Si la réinitialisation est appelée ultérieurement sur le signal, la gestion d'origine du signal sera réinstallée, restaurant le gestionnaire de signal non-go (le cas échéant).
Donc, le code ci-dessous capturera le sigint dans le code go et renverra la fonction dès que le sigint se produira.
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 }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!