首頁  >  文章  >  後端開發  >  用 Go 寫的 Python 擴充功能會忽略 Ctrl+C

用 Go 寫的 Python 擴充功能會忽略 Ctrl+C

王林
王林轉載
2024-02-13 14:09:101293瀏覽

用 Go 编写的 Python 扩展会忽略 Ctrl+C

php小編蘋果發現,使用Go編寫的Python擴充在處理Ctrl C訊號時可能會出現問題。通常情況下,當我們在命令列中按下Ctrl C時,會傳送一個SIGINT訊號給正在執行的程序,以請求其停止執行。然而,使用Go編寫的Python擴充似乎會忽略這個訊號,導致程式無法正常停止。這個問題對於使用Go編寫Python擴充的開發者來說是一個潛在的隱患,需要特別注意。所以,在開發過程中,我們應該尋找解決方案來解決這個問題,以確保程式的正常退出。

問題內容

我正在使用一個用go編寫的python驅動程序,該驅動程式連接到某個服務並進行一些處理。我們發現服務的「不健康」實例存在問題,這導致驅動程式卡住並且無法終止,除非我們 kill 進程。

做了一些實驗,我發現當執行用go 寫的擴充功能時,程式會忽略發出的ctrl c 指令,直到控制權回到python,而使用c 寫的擴充則不會發生這種情況,其中在執行時引發keyboardinterrupt c程式碼。我的問題是為什麼會發生這種情況以及是否有辦法規避這個問題或發出某種超時。嘗試使用 threading.timer 引發異常來模擬超時,但問題是該異常是在它自己的執行緒中引發的,並且不會中斷主執行緒。在python(cpython)3.93.10中測試。至於我寫的poc擴展,go版本是1.20.4,c編譯器是9.4.0

我會在下面留下一個小poc。

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")

go 擴充功能

package main

import (
   "c"
   "log"
   "time"
)

func helloworld(){
   log.println("hello world")
   time.sleep(10 * time.second)
   log.println("done sleeping")
}

func main(){
}

c 擴充功能

#include <stdio.h>

int helloWorld() {
    printf("Hello from C\n");
    sleep(10);
    printf("Done sleeping from C\n");

    return 0;
}

解決方法

我也遇到過同樣的情況。經過一番研究,我找到了解決方案。

根據這個答案

python 在 sigint 上安裝了一個訊號處理程序,它只是設定一個由主解釋器循環檢查的標誌。為了使該處理程序正常運作,python 解釋器必須執行 python 程式碼。

似乎在執行golang程式碼時,golang呼叫python安裝的sigint訊號處理程序來設定標誌。因此,當運行回 python 時,會偵測到鍵盤中斷。

來自 golang 文件

(當非go程式呼叫go程式碼時) 如果為非同步訊號呼叫 notify,則會為此訊號安裝 go 訊號處理程序。如果稍後對該訊號呼叫 reset,則該訊號的原始處理將重新安裝,恢復非 go 訊號處理程序(如果有)。

因此,下面的程式碼將在 go 程式碼中捕獲 sigint,並在 sigint 時立即傳回該函數。

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
}

以上是用 Go 寫的 Python 擴充功能會忽略 Ctrl+C的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除