为什么Django项目中的__init__模块在同一进程中加载两次?

6 投票
1 回答
762 浏览
提问于 2025-04-16 20:11

我正在尝试用Boost.Python把一个C语言库封装成一个高级的Python接口。这个C语言库的一个要求是,它的一个句柄在每个进程中只能分配一次。我希望能在Python这边通过使用模块全局变量来强制执行这个要求。

这是我Django组件模块的__init__.pyPyGenTL必须在每个进程中只创建一次!

import my_c_mod
import os

print "imager__init__()"
print os.getpid()
ptl = my_c_mod.PyGenTL()

这里有一点相关的Boost.Python代码

    BOOST_PYTHON_MODULE(my_c_mod)
    {
        using namespace boost::python;

        // Create the Python type object for our extension class and define __init__ function.
        class_<PyGenTL>("PyGenTL")
            .def("sys_info", &PyGenTL::SysInfo)
            .def("list_cameras", &PyGenTL::ListCameras)  // 
            .def("start_camera", &PyGenTL::StartCamera)  // 
        ;
    }

    PyGenTL::PyGenTL()
    {
        try {
            std::cout << "PyGenTL ctor(): allocating GenTL Lib." << std::endl;
            Detail::ThrowError(GCInitLib());
            Detail::ThrowError(TLOpen(&hTL));
        } catch (boost::exception& e) {
            std::cerr << "PyGenTL ERROR! ";
            std::cerr << boost::diagnostic_information(e);
            std::cerr << std::endl;
        }
    }

注意构造函数中的打印语句,以及init中的os.getpid()。这是来自Django进程的输出。请注意,在Python启动时会创建两个进程,这就是为什么会创建两个PyGenTL的原因。到目前为止,一切正常。

C:\work\svn\sw\branches\python\GenTlServer>python manage.py runserver
imager__init__()
2264
PyGenTL ctor(): allocating GenTL Lib.
imager__init__()
2912
PyGenTL ctor(): allocating GenTL Lib.
Validating models...

0 errors found
Django version 1.3, using settings 'GenTlServer.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

现在,在页面视图期间,__init__在同一个进程(2912)中又被调用了一次。

imager__init__()
2912
PyGenTL ctor(): allocating GenTL Lib.
ERROR (-1004): Requested module is in use.
PyGenTL ERROR! Requested module is in use.
[23/Jun/2011 18:02:22] "GET / HTTP/1.1" 500 76537

当然,我可以通过在C语言那边强制实现单例模式来解决我这个特定的问题,但在Python中应该怎么做呢?

1 个回答

2

因为它是通过两个不同的路径在加载的,路径在 sys.path 里。要保持导入的一致性;我建议你直接导入模块,而不是通过项目来导入,比如用 import <app>.<module> 这种方式。配置一个 WSGI 容器,这样你就不需要依赖 manage.pysys.path 的处理,这样会更好。

撰写回答