1

我在使用嵌入式 python 时遇到了困难。

我正在运行一个 DLL,每次调用某个函数时,我都想运行一个 Python 脚本。我想避免在函数末尾调用 Py_Finalize() 因为 Initialize/Finalize 调用大约需要 75 毫秒的时间,而我负担不起。

问题是,我似乎无法多次运行同一个 .py 文件而不会出错。

...
runResult = PyRun_SimpleFile(pyfileptr, pyfilename);
if (runResult)
{
    if (!PyErr_Occurred())
        return -4;
    PyErr_Print();
    return -3;
}
...

我总是第二次返回-4。我什至不知道这怎么可能,因为文档说 PyRun_SimpleFile 如果有异常则返回 -1 ,否则返回 0 ,但 PyErr_Occurred() 无异常返回 NULL 。

即使我正在运行的 Python 文件很简单

print("hi")

我最终得到了相同的结果,这当然让我相信这不是脚本本身生成的异常。

更新:看起来越来越像这是一个与 DLL 相关的问题,因为在独立应用程序中运行相同的代码不会显示问题。不过还是挺难过的。

4

1 回答 1

1

在这里。我基本上提出了两个问题,现在我的答案有些糟糕:

如何在不重新初始化的情况下运行 python 文件? 只是在第二次调用 PyRun_SimpleFile() 或 boost::python::exec_file() 之前不要调用 finalize 。

为什么 PyErr_Occurred() 在 PyRun_SimpleFile() 返回非零后返回 0? 简短的回答是我仍然不知道,但我最好的猜测是它与 DLL 实现和一些挂起或丢失的参考有关。

我根据 kichik 的建议使用了 boost::python,虽然我不会说它比基本 C API 更易于使用,但它更易于阅读。它也没有表现出丢失错误的问题,所以最终它解决了我的问题。即使在 DLL 中,我也能够毫无问题地进行两次连续的 exec_file() 调用。

因为我很难找到以我需要的方式使用的 boost::python 示例,所以我将把我的代码放在这里,稍微修剪一下以节省空间。当然,其中一些是特定于我的项目的,但作为一般示例,它可能仍然很有价值。

extern "C" LTPYTHON_API int ltPythonAnalyzeLog(char * analyzerfile, char * logfile, double timeWindow, int * results)
{

std::vector<int> countsVector;
Py_Initialize();
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
    // Example of adding a variable to the global namespace
main_namespace["scriptIsRunningThroughDll"] = boost::python::long_(1);

// Load arguments for the analyzer call
{
    int argc = 3;
    wchar_t * argv[3];

    //*... assemble wchar arguments for py script ... *

    PySys_SetArgv(argc, argv);
}

int startClock = clock();
try
{
    exec_file(analyzerfile, main_namespace);
}
catch(error_already_set const &)
{
            //*... some error handling ...*

    PyObject *ptype, *pvalue, *ptraceback;
    PyErr_Fetch(&ptype, &pvalue, &ptraceback);

    handle<> hType(ptype);
    object extype(hType);
    handle<> hTraceback(ptraceback);
    object traceback(hTraceback);

    //Extract error message
    std::string strErrorMessage = extract<std::string>(pvalue);
    long lineno = extract<long> (traceback.attr("tb_lineno"));

    FILE * outfile = fopen("ltpython-error.txt", "a");
    fprintf(outfile, "%d: %s\n", lineno, strErrorMessage);
    fflush(outfile);
    fclose(outfile);

    return -1;
}

    //*... grabbing a matrix of results that were created in the script ...*
object counts = main_namespace["sortedIndicationCounts"];
list countsList = extract<list>(counts);
int totalCount = 0;
for (int i = 0; i < len(countsList); i++)
{
    list singleCount = extract<list>(countsList[i]);
    countsVector.push_back(extract<int>(singleCount[1]));
    totalCount += countsVector[i];
}

    //*... returning the number of milliseconds that elapsed ...*
return clock() - startClock;
}

错误处理基于this answer

于 2013-08-27T15:57:32.083 回答