![](/img/trans.png)
[英]Import functions from dll (programmed in C++) into Python script when the dll has an embedded Python interpreter
[英]C++ application crashes when embedded Python interpreter tries to import external module a second time
如果我在不同的 pybind11::scoped_interpreter 會話中兩次導入外部模塊,應用程序將在 eval.h 中的函數 eval 中崩潰,如下行:
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
和
Exception thrown at 0x00007FFD710C4E0C (multiarray.cp36-win_amd64.pyd) in pybind-test.exe: 0xC0000005: Access violation writing location 0x000000000000000A.
namespace py = pybind11;
void test() {
try {
py::scoped_interpreter guard{};
py::object mainScope = py::module::import("__main__").attr("__dict__");
py::exec(
"import numpy\n",
mainScope);
}
catch (py::error_already_set const &pythonErr) { std::cout << pythonErr.what(); }
}
int main() {
test(); // Runs fine
test(); // Crashes at py::exec
}
我覺得這與 pybind11 的 embed.h 中的注釋有關:
可以通過再次調用
initialize_interpreter
來重新啟動解釋initialize_interpreter
。 使用 pybind11 創建的模塊可以安全地重新初始化。 但是,Python 本身不能完全卸載二進制擴展模塊,並且在解釋器重新啟動方面有幾個注意事項。 所有細節都可以在 CPython 文檔中找到。 簡而言之,並不是所有的解釋器內存都可以被釋放,無論是由於引用循環還是用戶創建的全局數據。
那么有沒有辦法兩次調用Python解釋器呢? 我有一個包含輔助 numpy 函數的 python 文件,我需要在 C++ 的算法執行的不同點調用這些函數。 這是否意味着我不能這樣做?
而不是使用py::scoped_interpreter
使用py::initialize_interpreter
和py::finalize_interpreter
。 根據需要多次呼叫口譯員。
警告:“Python 解釋器不是完全線程安全的為了支持多線程 Python 程序,有一個全局鎖,稱為全局解釋器鎖或GIL ”。
用法示例:
namespace py = pybind11;
void test() {
try {
py::object mainScope = py::module::import("__main__").attr("__dict__");
py::exec(
"import numpy\n",
mainScope);
}
catch (py::error_already_set const &pythonErr) { std::cout << pythonErr.what(); }
}
int main() {
py::initialize_interpreter();
test();
test();
py::finalize_interpreter();
}
根據這篇文章https://www.boost.org/doc/libs/1_47_0/libs/python/todo.html#pyfinalize-safety ,目前最好不要直接或通過 scoped_interpreter 調用 PyFinalize。
在調用 finalize 后重新加載模塊時可能會導致錯誤,然后再次初始化。 我在遵循當前批准的答案https://stackoverflow.com/a/51069948/5994043時遇到了這個問題。
https://www.boost.org/doc/libs/1_47_0/libs/python/todo.html#pyfinalize-safety
PyFinalize 安全:目前 Boost.Python 有幾個全局(或函數靜態)對象,它們的存在使引用計數不會下降到零,直到 Boost.Python 共享對象被卸載。 這可能會導致崩潰,因為當引用計數變為零時,沒有解釋器。 為了確保調用 PyFinalize() 的安全性,我們必須注冊一個 atexit 例程,該例程會銷毀這些對象並釋放所有 Python 引用計數,以便 Python 可以在仍有解釋器的情況下清理它們。 Dirk Gerrits 已承諾完成這項工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.