问题描述
#include <Python.h>
#include <fstream>
#include <iostream>
#include <string>
#include <filesystem>
#include <sys/types.h>
#include <dirent.h>
static const char * sPythonCode =
"class Test :\n"
" def __init__(self) : \n"
" self.disc_ = 0. \n"
" def getset(self) : \n"
" self.disc_ = 7. \n"
" return self.disc_ \n";
std::string writeFile()
{
static int iFile = 0;
std::string sFileName(std::string("test") + std::to_string(iFile));
std::ofstream out("py/" + sFileName + ".py");
out << sPythonCode;
out.flush();
out.close();
iFile++;
return sFileName;
}
static bool bPythonopen = false;
#define PYTHONPATHLEN 501
static void _PyInit()
{
if (!Py_IsInitialized())
{
Py_InitializeEx(0);
}
}
void openPython(void)
{
if (!bPythonopen)
{
const size_t szBufferN = 1000;
char acLoadpath[szBufferN];
const char *pypath = "./py";
_PyInit();
PyRun_SimpleString("import sys");
PyRun_SimpleString("print('python (%d.%d.%d) initialized' % (sys.version_info.major,sys.version_info.minor,sys.version_info.micro))");
PyRun_SimpleString("print('--------------------------')");
snprintf(acLoadpath,szBufferN,"sys.path.append('%s')",pypath);
PyRun_SimpleString(acLoadpath);
bPythonopen = true;
}
}
PyObject *loadpythonmodule(const char *acModule)
{
PyObject *pyModule = NULL;
if (bPythonopen && acModule && strcmp(acModule,""))
{
printf("%s\n",acModule);
pyModule = PyImport_ImportModule(acModule);
if (!pyModule)
{
PyErr_Print();
}
}
return pyModule;
}
void loadPython()
{
std::string sFileName = writeFile();
openPython();
//sleep(1);
PyObject *ppythonmodule = loadpythonmodule(sFileName.c_str());
if (ppythonmodule)
PyDict_DelItemString(PyImport_GetModuleDict(),PyModule_GetName((PyObject *)ppythonmodule));
}
int main(int argc,char **argv)
{
for (int i = 0; i < 10; i++)
{
loadPython();
}
}
我的工作环境:
- gcc 版本 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)
- 红帽企业 Linux 服务器 7.6 版 (Maipo)
- python 3.6.10 / 3.8.3 的问题
编译命令:
g++ pythontest.cpp -I/Opt/python/python3.6.10/include/python3.6m -L/opt/python/python3.6.10/lib -lpython3.6m
创建py目录:
mkdir py
输出示例:
python (3.6.10) initialized
--------------------------
test0
test1
test2
test3
ModuleNotFoundError: No module named 'test3'
test4
test5
ModuleNotFoundError: No module named 'test5'
test6
test7
ModuleNotFoundError: No module named 'test7'
test8
test9
ModuleNotFoundError: No module named 'test9'
很高兴知道:
- 如果我取消对 sleep 行的注释,效果会很好
- 如果我删除
iFile++
,它也会像在已经创建的文件之后使用一样工作 - 如果我在没有
rm -rf py
目录的情况下重新启动一秒钟,它也可以运行 - 如果我在
loadPython
函数中每次运行后删除文件并删除iFile++
它也可以工作 - 如果我使用
strace
启动可执行文件,我看不到问题
目前似乎 Python 加载程序没有看到磁盘上的文件,但是如果我打印目录中的内容,由于 dirent,我会看到 testx.py
请注意,我们在不同的 Linux 服务器上重现了该错误(不是硬件问题,甚至在 Windows 上),使用 Python 2.7.x 时它运行良好。
解决方法
每次修改模块文件夹时都应该调用 __import__('importlib').invalidate_caches()
以让 C Python 知道它必须再次读取目录。