在Python中运行C扩展比普通C更快
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了在Python中运行C扩展比普通C更快,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3937字,纯文字阅读大概需要6分钟。
内容图文
![在Python中运行C扩展比普通C更快](/upload/InfoBanner/zyjiaocheng/746/feeed9c342374063ad5509a828bed5cd.jpg)
我在C中实现了一个Python扩展,发现在Python中执行C函数要比从C main执行C代码快2倍.
但为什么这会更快?我希望普通的C在从Python调用时与从C调用时的性能完全相同.
这是我的实验:
>普通C计算代码(简单3用于矩阵 – 矩阵乘法)
> Plain C main函数调用mmult()函数
> Python扩展包装器来调用mmult()函数
>所有时间都完全在C代码中发生
这是我的结果:
纯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: %fus\n",elapsedTime);
}
–mmult.h ——-
#include <stdint.h>
void mmult(int32_t a[1024],int32_t b[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, t2;
gettimeofday(&t1, NULL);
mmult(a,b,c);
gettimeofday(&t2, NULL);
double elapsedTime = (t2.tv_usec - t1.tv_usec) + (t2.tv_sec - t1.tv_sec)*1000000;
printf("elapsed time: %fus\n",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,b,c);
Py_RETURN_NONE;
}
/* define functions in module */
static PyMethodDef TheMethods[] = {
{"mmult_wrapper", mmult_wrapper, METH_VARARGS, "your c function"},
{NULL, NULL, 0, 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,1024,dtype='int32').reshape(32,32))
b = np.ndarray((32,32),dtype='int32',buffer=np.linspace(1,1024,1024,dtype='int32').reshape(32,32))
c = np.ndarray((32,32),dtype='int32',buffer=np.zeros((32,32),dtype='int32'))
c_module.mmult_wrapper(a,b,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中的初始顺序矩阵乘法代码更快.
内容总结
以上是互联网集市为您收集整理的在Python中运行C扩展比普通C更快全部内容,希望文章能够帮你解决在Python中运行C扩展比普通C更快所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。