【问题标题】:What's the performance of PyImport_ImportModule(), and what are the best practices for using it?PyImport_ImportModule() 的性能如何,使用它的最佳实践是什么?
【发布时间】:2021-11-04 02:19:52
【问题描述】:

我有一个内部循环 C 函数(在我的例子中)构造一个 Python datetime 对象:

PyObject* my_inner_loop_fn(void* some_data) {
    PyObject* datetime = PyImport_ImportModule("datetime");
    if (datetime == NULL) return NULL;
    PyObject* datetime_date = PyObject_GetAttrString(datetime, "date");
    PyObject* result = NULL;
    if (datetime_date != NULL) {
        /* long long my_year, my_month, my_day = ... ; */
        PyObject* args = Py_BuildValue("(LLL)", my_year, my_month, my_day);
        res = PyObject_Call(datetime_date, args, NULL);
        Py_XDECREF(args);
    }
    Py_XDECREF(datetime_date);
    Py_DECREF(datetime);
    return result;
}

我的问题:

  • PyImport_ImportModule("datetime") 是否每次都从头开始重新加载整个模块,还是缓存?
  • 如果没有缓存:
    • 缓存它的首选方法是什么?
    • 尝试导入其他模块的最早时间是什么时候是安全的?例如,我可以将其分配给全局变量吗?

我想避免为导入支付高昂的费用,因为该功能经常运行。以上预期是性能代码吗?

【问题讨论】:

    标签: python python-import cpython python-c-api


    【解决方案1】:

    PyImport_ImportModule("datetime") 是否每次都从头开始重新加载整个模块,还是缓存?

    标准行为是to first check sys.modules to see if the module has already been imported 并尽可能返回它。只有导入不成功才会重新加载。

    您显然可以通过将一些具有可见副作用的代码放入模块中并多次导入(例如打印语句)来测试自己。

    模块导入系统可自定义的,所以我相信另一个模块可以选择修改该行为(例如,pyximport 模块可以选择始终重新加载) .因此,它不是 100% 保证的。

    它可能仍然值得缓存,因为进行查找需要一些成本 - 这是在不必自己缓存它的便利性和速度之间取得平衡。

    尝试导入其他模块的最早时间是什么时候是安全的?

    Python 解释器初始化后就安全了。如果您将 Python 嵌入到 C/C++ 程序中,这是您需要考虑的问题。如果您正在编写 Python 扩展模块,那么您可以确信解释器已为要导入的模块进行了初始化。

    例如,我可以将它分配给全局变量吗?

    是的。但是,全局变量使您的模块难以支持干净地卸载和重新加载。许多 C 扩展选择不担心这一点。但是,PyModule_GetState 机制旨在支持此用例,因此您可以选择将缓存置于扩展模块状态。

    【讨论】:

      猜你喜欢
      • 2017-09-01
      • 1970-01-01
      • 2011-11-21
      • 2010-10-30
      • 2018-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多