Dan*_*iel 14 python numpy intel-mkl
我试图mkl_set_num_threads
像这样设置numpy计算的线程数
import numpy
import ctypes
mkl_rt = ctypes.CDLL('libmkl_rt.so')
mkl_rt.mkl_set_num_threads(4)
Run Code Online (Sandbox Code Playgroud)
但我不断收到分段错误:
Program received signal SIGSEGV, Segmentation fault.
0x00002aaab34d7561 in mkl_set_num_threads__ () from /../libmkl_intel_lp64.so
Run Code Online (Sandbox Code Playgroud)
获取线程数是没问题的:
print mkl_rt.mkl_get_max_threads()
Run Code Online (Sandbox Code Playgroud)
如何让我的代码工作?或者是否有其他方法可以在运行时设置线程数?
Dan*_*iel 14
Ophion以正确的方式引导我.尽管有文档,但必须mkl_set_num_thread
通过引用传递参数.
现在我已经定义了函数,用于获取和设置线程
import numpy
import ctypes
mkl_rt = ctypes.CDLL('libmkl_rt.so')
mkl_get_max_threads = mkl_rt.mkl_get_max_threads
def mkl_set_num_threads(cores):
mkl_rt.mkl_set_num_threads(ctypes.byref(ctypes.c_int(cores)))
mkl_set_num_threads(4)
print mkl_get_max_threads() # says 4
Run Code Online (Sandbox Code Playgroud)
他们按预期工作.
编辑:根据Rufflewind,C函数的名称是以大写形式编写的,它按值来表示参数:
import ctypes
mkl_rt = ctypes.CDLL('libmkl_rt.so')
mkl_set_num_threads = mkl_rt.MKL_Set_Num_Threads
mkl_get_max_threads = mkl_rt.MKL_Get_Max_Threads
Run Code Online (Sandbox Code Playgroud)
长话短说,使用MKL_Set_Num_Threads
和它的CamelCased朋友从Python调用MKL时.这同样适用于C如果你不这样做#include <mkl.h>
.
该MKL文件似乎表明,在C正确的类型签名是:
void mkl_set_num_threads(int nt);
Run Code Online (Sandbox Code Playgroud)
好的,让我们尝试一个最小的程序:
void mkl_set_num_threads(int);
int main(void) {
mkl_set_num_threads(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
与海湾合作委员会,并编译热潮,Segmentation fault
再一次.所以似乎问题不仅限于Python.
通过调试器(GDB)运行它会显示:
Program received signal SIGSEGV, Segmentation fault.
0x0000… in mkl_set_num_threads_ ()
from /…/mkl/lib/intel64/libmkl_intel_lp64.so
Run Code Online (Sandbox Code Playgroud)
等一下,mkl_set_num_threads_
?? 这就是Fortran语言版本的mkl_set_num_threads
!我们最终如何调用Fortran版本?(请记住,Fortran的调用约定要求将参数作为指针而不是值传递.)
事实证明,文档是一个完整的外观.如果您实际检查最近版本的MKL的头文件,您会发现这个可爱的小定义:
void MKL_Set_Num_Threads(int nth);
#define mkl_set_num_threads MKL_Set_Num_Threads
Run Code Online (Sandbox Code Playgroud)
......现在一切都很有意义!正确的函数调用(对于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_
…
Run Code Online (Sandbox Code Playgroud)
尽管文档中只有C和Fortran变体,为什么英特尔在一个函数中添加了四种不同的变体?我不确定,但我怀疑这是为了兼容不同的Fortran编译器.你看,Fortran调用约定不是标准化的.不同的编译器会以不同方式破坏函数的名称:
甚至可能还有其他方法我不知道.这个技巧允许MKL库与大多数Fortran编译器一起使用而不做任何修改,缺点是C函数需要被"修复"以便为Fortran调用约定的3个变体腾出空间.