gpt4 book ai didi

python - 当 import_array 不在同一翻译单元中时出现段错误

转载 作者:太空狗 更新时间:2023-10-29 21:49:41 26 4
gpt4 key购买 nike

我在正确初始化 NumPy C API 时遇到问题。我想我已经将问题隔离到从不同的翻译单元调用 import_array,但我不知道为什么这很重要。

最小工作示例:

header1.hpp

#ifndef HEADER1_HPP
#define HEADER1_HPP
#include <Python.h>
#include <numpy/npy_3kcompat.h>
#include <numpy/arrayobject.h>

void initialize();

#endif

file1.cpp

#include "header1.hpp"

void* wrap_import_array()
{
import_array();
return (void*) 1;
}

void initialize()
{
wrap_import_array();
}

file2.cpp

#include "header1.hpp"

#include <iostream>

void* loc_wrap_import_array()
{
import_array();
return (void*) 1;
}

void loc_initialize()
{
loc_wrap_import_array();
}

int main()
{
Py_Initialize();
#ifdef USE_LOC_INIT
loc_initialize();
#else
initialize();
#endif
npy_intp dims[] = {5};
std::cout << "creating descr" << std::endl;
PyArray_Descr* dtype = PyArray_DescrFromType(NPY_FLOAT64);
std::cout << "zeros" << std::endl;
PyArray_Zeros(1, dims, dtype, 0);
std::cout << "cleanup" << std::endl;
return 0;
}

编译器命令:

g++ file1.cpp file2.cpp -o segissue -lpython3.4m -I/usr/include/python3.4m -DUSE_LOC_INIT
./segissue
# runs fine

g++ file1.cpp file2.cpp -o segissue -lpython3.4m -I/usr/include/python3.4m
./segissue
# segfaults

我已经使用 Clang 3.6.0、GCC 4.9.2、Python 2.7 和 Python 3.4(使用适当修改的 wrap_import_array 进行了测试,因为这在 Python 2.x 和 3.x 之间是不同的。 X)。各种组合都给出相同的结果:如果我不调用 loc_initialize,程序将在 PyArray_DescrFromType 调用中出现段错误。我有 NumPy 版本 1.8.2。作为引用,我在 Ubuntu 15.04 中运行它。

最让我困惑的是this C++ NumPy wrapper似乎可以在不同的翻译单元中调用 import_array

我错过了什么?为什么我必须从同一个翻译单元调用 import_array 才能使其真正生效?更重要的是,当我从不同的翻译单元(如 Boost.NumPy 包装器)调用 import_array 时,如何让它工作?

最佳答案

在深入研究 NumPy header 后,我想我找到了解决方案:

numpy/__multiarray_api.h 中,有一个部分涉及内部 API 缓冲区的位置。为简洁起见,这里是相关的片段:

#if defined(PY_ARRAY_UNIQUE_SYMBOL)
#define PyArray_API PY_ARRAY_UNIQUE_SYMBOL
#endif

#if defined(NO_IMPORT) || defined(NO_IMPORT_ARRAY)
extern void **PyArray_API;
#else
#if defined(PY_ARRAY_UNIQUE_SYMBOL)
void **PyArray_API;
#else
static void **PyArray_API=NULL;
#endif
#endif

看起来这是为了允许多个模块定义自己的内部 API 缓冲区,每个模块必须在其中调用自己的 import_array 定义。

让多个翻译单元使用相同的内部 API 缓冲区的一致方法是在每个模块中,将 PY_ARRAY_UNIQUE_SYMBOL 定义为某个库的唯一名称,然后每个翻译单元除了其中的那个定义了 import_array 包装器 定义了 NO_IMPORTNO_IMPORT_ARRAY。顺便说一句,ufunc 功能有类似的宏:PY_UFUNC_UNIQUE_SYMBOLNO_IMPORT/NO_IMPORT_UFUNC

修改后的工作示例:

header1.hpp

#ifndef HEADER1_HPP
#define HEADER1_HPP

#ifndef MYLIBRARY_USE_IMPORT
#define NO_IMPORT
#endif

#define PY_ARRAY_UNIQUE_SYMBOL MYLIBRARY_ARRAY_API
#define PY_UFUNC_UNIQUE_SYMBOL MYLIBRARY_UFUNC_API

#include <Python.h>
#include <numpy/npy_3kcompat.h>
#include <numpy/arrayobject.h>

void initialize();

#endif

file1.cpp

#define MYLIBRARY_USE_IMPORT
#include "header1.hpp"

void* wrap_import_array()
{
import_array();
return (void*) 1;
}

void initialize()
{
wrap_import_array();
}

file2.cpp

#include "header1.hpp"

#include <iostream>

int main()
{
Py_Initialize();
initialize();
npy_intp dims[] = {5};
std::cout << "creating descr" << std::endl;
PyArray_Descr* dtype = PyArray_DescrFromType(NPY_FLOAT64);
std::cout << "zeros" << std::endl;
PyArray_Zeros(1, dims, dtype, 0);
std::cout << "cleanup" << std::endl;
return 0;
}

我不知道这个 hack 有什么陷阱,或者是否有更好的选择,但这似乎至少可以编译和运行,没有任何段错误。

关于python - 当 import_array 不在同一翻译单元中时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31971185/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com