20

我正在將Python解釋器嵌入到C程序中。但是,通過PyRun_SimpleString()運行一些python腳本時,可能會發生無限循環或執行時間過長。考慮PyRun_SimpleString("while 1: pass");爲了防止主程序阻塞,我想我可以在一個線程中運行解釋器。停止嵌入式Python

如何在不殺死整個進程的情況下停止在線程中運行的嵌入式解釋器中執行python腳本?

是否有可能將異常傳遞給解釋器?我是否應該將腳本包裝在可以聽信號的其他腳本下?

PS:我可以運行在蟒蛇一個單獨的進程,但是這不是我想要的 - 除非是萬不得已......


更新:

所以,現在工作。謝謝丹尼斯Otkidach,再次!

如果我看到這個正確的話,你必須做兩件事:告訴解釋器停止並且在你的PyRun_SimpleString()正在運行的同一線程中運行return -1

要停止,有一些可能性:PyErr_SetString(PyExc_KeyboardInterrupt, "...")PyErr_SetInterrupt() - 第一個可能會讓Python運行更多指令,然後停止,稍後停止立即執行。

return -1您使用Py_AddPendingCall()將函數調用注入到Python執行中。文檔從2.7和3.1版開始提到它,但它也在較早的Pythons上運行(這裏是2.6)。從2.7和3.1開始,它也應該是線程安全的,這意味着你可以在不獲取GIL(?)的情況下調用它。

所以人們可以波紋管改寫例如:

int quit() { 
    PyErr_SetInterrupt(); 
    return -1; 
} 

回答

10

您可以使用Py_AddPendingCall()添加在下一個檢查時間間隔內調用的函數引發異常(有關更多信息,請參閱sys.setcheckinterval()上的文檔)。這裏是Py_Exit()調用(這確實對我的作品,但可能不是你所需要的)爲例,與Py_Finalize()PyErr_Set*()進行更換:

int quit(void *) { 
    Py_Exit(0); 
} 


PyGILState_STATE state = PyGILState_Ensure(); 
Py_AddPendingCall(&quit, NULL); 
PyGILState_Release(state); 

這應該是足以讓任何純Python代碼。但是請注意,一些C函數可以運行一段時間作爲一個單一的操作(有一個長時間運行正則表達式搜索的例子,但我不確定它仍然相關)。

+0

這看起來很有趣,但是它不是最新的Python嗎? (2.7阿爾法今天才出來。) 但是,我可以升級到Python 3.1 - 但那又如何?我應該通過'Py_AddPendingCall()'註冊哪個函數? 'PyErr_SetString()'? 'Py_Exit()'? 'Py_Finalize()'? – 2009-09-15 18:28:48

+0

Py_AddPendingCall至少存在於python 2.0中(在ceval.h中定義)。我爲我的答案添加了一個示例代碼。 – 2009-09-16 07:52:14

+0

謝謝!有用! – 2009-09-16 11:43:54

1

好Python解釋器將不得不從嵌入程序一個單獨的線程來運行,或者您根本不會有機會打斷解釋。

當你有這個問題時,也許你可以使用其中一個Python API異常調用來觸發解釋器中的異常?請參閱Python C API Exceptions