在Python中运行C扩展比普通C更快
我在C中实现了一个
Python扩展,发现在
Python中执行C函数要比从C main执行C代码快2倍.
但为什么这会更快?我希望普通的C在从Python调用时与从C调用时的性能完全相同. 这是我的实验: >普通C计算代码(简单3用于矩阵 – 矩阵乘法) 这是我的结果: 纯C – 85us Python扩展 – 36us 继承我的代码: –mmult.cpp ———- #include "mmult.h" void mmult(int32_t a[1024],int32_t b[1024],int32_t c[1024]) { struct timeval t1,t2; gettimeofday(&t1,NULL); for(int i=0; i<32; i=i+1) { for(int j=0; j<32; j=j+1) { int32_t result=0; for(int k=0; k<32; k=k+1) { result+=a[i*32+k]*b[k*32+j]; } c[i*32+j] = result; } } gettimeofday(&t2,NULL); double elapsedTime = (t2.tv_usec - t1.tv_usec) + (t2.tv_sec - t1.tv_sec)*1000000; printf("elapsed time: %fusn",elapsedTime); } –mmult.h ——- #include <stdint.h> void mmult(int32_t a[1024],int32_t c[1024]); –main.cpp —— #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include "mmult.h" int main() { int* a = (int*)malloc(sizeof(int)*1024); int* b = (int*)malloc(sizeof(int)*1024); int* c = (int*)malloc(sizeof(int)*1024); for(int i=0; i<1024; i++) { a[i]=i+1; b[i]=i+1; c[i]=0; } struct timeval t1,NULL); mmult(a,b,c); gettimeofday(&t2,elapsedTime); free(a); free(b); free(c); return 0; } 以下是我如何编译main: gcc -o main main.cpp mmult.cpp -O3 –wrapper.cpp —– #include <Python.h> #include <numpy/arrayobject.h> #include "mmult.h" static PyObject* mmult_wrapper(PyObject* self,PyObject* args) { int32_t* a; PyArrayObject* a_obj = NULL; int32_t* b; PyArrayObject* b_obj = NULL; int32_t* c; PyArrayObject* c_obj = NULL; int res = PyArg_ParseTuple(args,"OOO",&a_obj,&b_obj,&c_obj); if (!res) return NULL; a = (int32_t*) PyArray_DATA(a_obj); b = (int32_t*) PyArray_DATA(b_obj); c = (int32_t*) PyArray_DATA(c_obj); /* call function */ mmult(a,c); Py_RETURN_NONE; } /* define functions in module */ static PyMethodDef TheMethods[] = { {"mmult_wrapper",mmult_wrapper,METH_VARARGS,"your c function"},{NULL,NULL,NULL} }; static struct PyModuleDef cModPyDem = { PyModuleDef_HEAD_INIT,"mmult","Some documentation",-1,TheMethods }; PyMODINIT_FUNC PyInit_c_module(void) { PyObject* retval = PyModule_Create(&cModPyDem); import_array(); return retval; } –setup.py —– import os import numpy from distutils.core import setup,Extension cur = os.path.dirname(os.path.realpath(__file__)) c_module = Extension("c_module",sources=["wrapper.cpp","mmult.cpp"],include_dirs=[cur,numpy.get_include()]) setup(ext_modules=[c_module]) –code.py —– import c_module import time import numpy as np if __name__ == "__main__": a = np.ndarray((32,32),dtype='int32',buffer=np.linspace(1,1024,dtype='int32').reshape(32,32)) b = np.ndarray((32,32)) c = np.ndarray((32,buffer=np.zeros((32,dtype='int32')) c_module.mmult_wrapper(a,c) 下面是我如何编译Python扩展: python3.6 setup_sw.py build_ext --inplace UPDATE 我已经更新了mmult.cpp代码,以便在内部运行3到1,000,000次迭代.这导致非常相似的时间: 纯C – 27us Python扩展 – 27us 解决方法
85微秒的延迟太小,无法可靠且重复地测量.例如,CPU cache效果(或
context switches或
paging)可能支配计算时间(并改变它以使该时间无意义).
(我猜你在Linux / x86-64上) 根据经验,尝试至少持续运行半秒钟,并重复基准测试几次.您也可以使用time(1)进行测量. 另请参阅time(7).有几种时间概念(经过“实际”时间,单调时间,进程CPU时间,线程CPU时间等).您可以考虑使用clock(3)或clock_gettime(2)来测量时间. 顺便说一句,您可以使用更新版本的GCC(2017年11月,GCC7和几周GCC8)进行编译,并且您希望使用gcc -march = native -O3进行编译以进行基准测试.尝试其他optimization options和调整.您也可以尝试其他编译器,例如Clang/LLVM. 另请参阅this对相关问题的回答(关于并行化).可能numpy软件包使用(内部)类似技术(在Python GIL之外),因此可能比C中的初始顺序矩阵乘法代码更快. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |