长话短说,当从Python调用MKL时,请使用
MKL_Set_Num_Threads
及其驼峰式的伙伴。如果您不使用
#include <mkl.h>
,则同样适用于C语言。
MKL文档似乎表明C语言中正确的类型签名为:
void mkl_set_num_threads(int nt);
好的,那么我们试试一个最简程序:
void mkl_set_num_threads(int);
int main(void) {
mkl_set_num_threads(1);
return 0;
}
使用GCC编译后,
砰,再次出现
分段错误
。所以问题似乎不仅限于Python。
通过调试器(GDB)运行它可以发现:
Program received signal SIGSEGV, Segmentation fault.
0x0000… in mkl_set_num_threads_ ()
from /…/mkl/lib/intel64/libmkl_intel_lp64.so
稍等一下,“mkl_set_num_threads_”??这是“mkl_set_num_threads”的
Fortran版本!我们是怎么调用Fortran版本的?(请记住,Fortran的调用约定要求通过
指针而不是按值传递参数。)
事实证明文档完全是个幌子。如果你实际检查MKL最近版本的头文件,你会发现一个可爱的定义:
void MKL_Set_Num_Threads(int nth);
#define mkl_set_num_threads MKL_Set_Num_Threads
现在一切都有意义了!正确的函数调用(对于C代码)是MKL_Set_Num_Threads
,而不是mkl_set_num_threads
。检查符号表发现实际上定义了四种不同的变体:
nm -D /…/mkl/lib/intel64/libmkl_rt.so | grep -i mkl_set_num_threads
00000000000e3060 T MKL_SET_NUM_THREADS
…
00000000000e30b0 T MKL_Set_Num_Threads
…
00000000000e3060 T mkl_set_num_threads
00000000000e3060 T mkl_set_num_threads_
…
为什么英特尔在文档中只有C和Fortran两种变体,却提供了四种不同的函数变体?我不能确定,但我怀疑是为了与不同的Fortran编译器兼容。你知道,Fortran调用约定并没有标准化。不同的编译器会以不同的方式
改变函数名称:一些使用大写字母,一些使用小写字母加下划线,还有一些则完全不添加修饰符。甚至可能还有其他我不知道的方式。这个技巧允许MKL库在
大多数Fortran编译器上使用而无需进行任何修改,缺点是需要对C函数进行"改名"以容纳三种Fortran调用约定的变体。
mkl
作为模块导入。我想知道背后发生了什么。 - user2379410