来源 | 大数据文摘

编译:啤酒泡泡、宁静

Python是社区里最受喜爱的编程语言!它是目前为止最易使用的语言,因为它的代码短小精悍,符合人们的思维方式,也符合人们的阅读习惯。

但是你会经常听到有人吐槽Python,尤其是有些C语言的大牛吐槽Python速度慢。

他们说得没错,相比其他高级程序设计语言,如C语言来说,Python确实速度很慢,这主要是因为C语言更面向计算机底层,像一些单片机、电路板的设计都使用C语言,C语言和汇编语言之间的转换也更快,但是“every coin has two sides”,没有完美无缺的编程语言,C语言也有着其诸如代码量大、面向过程的一些缺点,如何让Python兼顾C语言速度方面的优点呢?

一个很形象的例子,就像上图展示的一样,赛车手需要兼顾汽车的发动引擎的内耗磨损,也要兼顾赛车的运行速度,那么,如何在两者之间取得平衡呢?

其实有很多可以提高运行速度的办法,比如:

  • 利用多进程库来使用所有的CPU内核;

  • 如果你正在使用NumPy,Pandas,或是Scikit-Learn库,那么可以使用Rapids来提高GPU的处理速度。

但是这只针对你的任务可以并行的情况,例如数据预处理、矩阵操作等,上述办法都很棒,可是如果你只使用纯Python语言,那该怎么办呢?再比如,你必须使用一个很大的for循环,而且因为数据必须被顺序处理导致你无法使用矩阵,在这种情况下,有没有办法提高Python本身的速度呢?

Cython就是用来加速纯Python代码的。

什么是Cython?

从本质上讲,Cython是Python和C/C++的桥梁。它允许你对Python代码稍作修改,然后把Python代码直接翻译成C语言代码。

你唯一需要修改Python代码的地方就是在每一个变量前面加上它的类型,通常,我们在Python里会这样声明变量:

x = 0.5

如果使用Cython,我们会给变量加上它的类型:

cdef float x = 0.5

这会告诉Cython,我们的变量是浮点型变量,这和我们在C语言中的操作一样。使用纯Python语言,变量的数据类型在赋值后被自动定义。Cython这种显式的变量声明方法使得Python代码转换成C代码成为可能,因为C语言要求变量的数据类型必须在声明变量时写出来。

使用pip安装Cython只需一行代码:

pip install cython

Cython的数据类型

使用Cython时,Cython提供两类类型,一类用于变量,一类用于函数。

对于变量,我们可以这样写(请注意,这些类型都来自C/C++):

  • cdef int a, b, c
  • cdef char *s
  • cdef float x = 0.5 (single precision)
  • cdef double x = 63.4 (double precision)
  • cdef list names
  • cdef dict goals_for_each_play
  • cdef object card_deck

对于函数,我们可以这样写:

  • def – 普通的Python函数,只用Python解释器
  • cdef – Cython专用函数,不能通过纯Python代码使用该函数,必须在Cython内使用
  • cpdef – C语言和Python共用。可以通过C语言或者Python代码使用该函数

有了对Cython的了解,我们可以更进一步,开始加速我们的代码了!

使用Cython提高代码的运行速度

首先,我们建立一个Python代码的基准——使用一个for循环来计算某个数的阶乘。以下是用纯Python语言写的代码:

def test(x):   y = 1  for i in range(1, x+1):    y *= i return y

使用Cython写出的函数和纯Python代码写出的函数很类似,首先,我们要确保Cython代码文件的扩展名是.pyx。然后,我们唯一修改的地方就是在我们已声明的每个变量和函数前加上它们的类型,run_cython.pyx代码如下:

cpdef int test(int x):   cdef int y = 1 cdef int i  for i in range(1, x+1):    y *= i return y

请注意,函数前有cpdef,以确保我们可以通过Python调用该函数。同时请注意,for循环里的变量i也有类型信息,你需要设定函数中所有变量的类型,这样C语言编译器才能知道需要使用什么类型!
接下来,创建一个setup.py文件,把Cython代码翻译成C代码:

from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules = cythonize('run_cython.pyx'))

然后执行汇编过程,在命令行输入如下命令:

python setup.py build_ext --inplace

我们的C代码已经被编译了,可以使用了!你可以在文件夹里看见你的Cython代码,你有了所有运行C代码所需要的文件,包括run_cython.c文件,文摘菌在win10系统尝试后文件夹结构如下:

打开run_cython.c后的部分代码(代码有点长,此处只展示开头变量声明和结尾的函数实现)

/***the beginning part of the code***/
/* Generated by Cython 0.29.13 */
/* BEGIN: Cython Metadata
{   "distutils": {    "name": "run_cython",   "sources": [  "run_cython.pyx"  ]   },  "module_name": "run_cython"
}
END: Cython Metadata */ #define PY_SSIZE_T_CLEAN
#include "Python.h"
#ifndef Py_PYTHON_H #error Python headers needed to compile C extensions, please install development version of Python.
#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)    #error Cython requires Python 2.6+ or Python 3.3+.
#else
#define CYTHON_ABI "0_29_13"
#define CYTHON_HEX_VERSION 0x001D0DF0
#define CYTHON_FUTURE_DIVISION 0
#include <stddef.h>
#ifndef offsetof    #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
#endif
#if !defined(WIN32) && !defined(MS_WINDOWS) #ifndef __stdcall   #define __stdcall   #endif  #ifndef __cdecl #define __cdecl #endif  #ifndef __fastcall  #define __fastcall  #endif
#endif
#ifndef DL_IMP  /****the end part of the code***/
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {  Py_ssize_t ival;    PyObject *x;
#if PY_MAJOR_VERSION < 3 if (likely(PyInt_CheckExact(b))) {  if (sizeof(Py_ssize_t) >= sizeof(long)) return PyInt_AS_LONG(b);    else    return PyInt_AsSsize_t(b);  }
#endif  if (likely(PyLong_CheckExact(b))) { #if CYTHON_USE_PYLONG_INTERNALS const digit* digits = ((PyLongObject*)b)->ob_digit; const Py_ssize_t size = Py_SIZE(b);    if (likely(__Pyx_sst_abs(size) <= 1)) { ival = likely(size) ? digits[0] : 0;   if (size == -1) ival = -ival;    return ival;    } else {    switch (size) { case 2: if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));    }   break;  case -2:    if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));   }   break;  case 3: if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));  }   break;  case -3:    if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); }   break;  case 4: if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));    }   break;  case -4:    if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0]));   }   break;  }   }   #endif  return PyLong_AsSsize_t(b); }   x = PyNumber_Index(b); if (!x) return -1;  ival = PyInt_AsSsize_t(x); Py_DECREF(x);   return ival;
}
static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False);
}
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {   return PyInt_FromSize_t(ival);
}   #endif /* Py_PYTHON_H

现在我们可以测试我们全新的、速度超快的C代码了!看看下面的代码,它是比较Python代码和Cython代码速度的测试:

import run_python
import run_cython
import time number = 10    start = time.time()
run_python.test(number)
end =  time.time() py_time = end - start
print("Python time = {}".format(py_time))    start = time.time()
run_cython.test(number)
end =  time.time() cy_time = end - start
print("Cython time = {}".format(cy_time))    print("Speedup = {}".format(py_time /

代码很容易理解,我们用Python的方式导入我们的文件,然后也像Python那样运行我们的函数!
只需稍作修改,Cython就可以帮你加速几乎所有的纯Python代码。值得注意的是,你使用的循环越多、需要筛选处理的数据越多,Cython就越能发挥加速的作用。
请看下面的表格,它记录了Cython在计算不同数阶乘的运行速度,number的值从10到10000000,使用Cython,我们的速度提高了36倍!

以上对Cython的介绍,希望可以给习惯使用Python进行编程的读者带来帮助。文摘菌也强势安利这款Cython加速器,带你在Python的道路上驰骋!
相关报道:

https://towardsdatascience.com/use-cython-to-get-more-than-30x-speedup-on-your-python-code-f6cb337919b6

—————————————

往期精彩:

  • 小红书,“黄”了

  • 苹果谷歌双双被曝,你的手机正在窃听你的生活

  • 遇事不决赖毛子,美国这次打算封杀变脸APP

提速30倍!这个加速包让Python代码飞起来相关推荐

  1. java 下载加速_Java实现大文件下载,提速30倍!想学?我教你啊!

    前言 兄弟们看到这个标题可能会觉得是个标题党,为了解决疑虑,我们先来看下最终的测试结果: 测试云盘下载的文件 46M,自己本地最大下载速度 2M 1. 单线程下载,总耗时: 603s img 2. 多 ...

  2. Java实现大文件多线程下载,提速30倍!想学?我教你啊

    前言 在上一篇文章 <面试官不讲武德>对Java初级程序猿死命摩擦Http协议 中,我们有提到大文件下载和断点续传,本篇我们就来开发一个多线程文件下载器,最后我们用这个多线程下载器来突破云 ...

  3. python 大项目使用cython_提升6.75倍!利用Cython为Python代码加速

    全文共2012字,预计学习时长4分钟 图片来源:Unsplash 如果你曾经用Python编写过代码,可能会发现等待某些代码块执行的时间比预期要长.尽管可以通过一些方法提高其代码效率,但它的反应速度仍 ...

  4. 百度PRNN:增强GPU伸缩性,RNN训练最高提速30倍(源码下载)

    尽管有各种深度学习加速器,神经网络的大小依然受限于计算平台的能力.百度硅谷人工智能实验室高级研究员Greg Diamos在最近的ICML 2016上发表了一篇PRNN(Persistent RNNs) ...

  5. python 预编译加速_让Python代码运行更快的最佳方式

    Python因其强大.灵活且易于使用等特性,而赢得了声誉.这些优点使其在各种各样的应用程序.工作流程和领域中得到了广泛应用.但是就语言的设计,也就是它天然的解释能力还有它的运行时的动态性而言,Pyth ...

  6. python计算密集型提速_利用Cython加速计算密集型python任务

    何为计算密集型任务 下面贴上网上找到的描述计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率.对视频进行高清解码等等,全靠CPU的运算能力.这种计算密集型任务虽然也可以用多任务完成 ...

  7. (译)用多重赋值和元组解包提高python代码的可读性

    原文链接(侵删): http://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/ 无论我是教pytho ...

  8. python numba_用 Numba 加速你的 Python 代码,性能轻松大提升

    Numba 简介 Numba 是 Python 的一个 JIT (just-in-time) 编译器,最适用于 NumPy 数组.函数,以及 Python 循环.基本上,用法就是给原来的 Python ...

  9. 用包管理python代码,提高开发效率

    有一个月没更新博客文章了,主要原因是我在摸索新知识,探索未知,以后有机会写写这段时间的成果,将会在linux编程专题继续更新. 现在我打算写一个新的专题Python编程来总结过去点点滴滴的收获.这个专 ...

  10. python for循环加速_干货总结,24招加速你的Python代码,值得收藏

    一,分析代码运行时间 第1式,测算代码运行时间 平凡方法 快捷方法(jupyter环境) 第2式,测算代码多次运行平均时间 平凡方法 快捷方法(jupyter环境) 第3式,按调用函数分析代码运行时间 ...

最新文章

  1. startuml如何画流程图_因为流程图没画好SCI被拒稿!看完师姐的攻略后我被吊打了!...
  2. c++类中成员的构造顺序
  3. 在显示器上面看到Lo的时候应该怎么想呢?一种可能的解释
  4. Windows版nacos启动报错(nacos安装路径问题)
  5. 15个最受欢迎的Python开源框架
  6. 【译】适合dba和开发者的mysql最佳实践
  7. Visual Studio 2015 初体验
  8. Java 死锁及解决方法
  9. C++--第20课 - 函数模板
  10. matlab运行C程序
  11. 视频教程-华为HCNA网络工程师【从入门到精通】自学视频[肖哥]-华为认证
  12. ENVI学习总结(九)——图像裁剪
  13. luogu P4173 残缺的字符串
  14. 被破解毁掉的国产游戏之光
  15. [Python]第一章(建议收藏)
  16. 神经网络编程的34个案例,人工神经网络编程内容
  17. SAP 常用增强记录文档
  18. 如何查看和修改Windows的主机名
  19. 【DockerCE】Docker-CE 20.10.14正式版发布
  20. 64位计算机最大寻址,为什么说32位操作系统的寻址空间是4G

热门文章

  1. 颠覆你想象的150个故事(2)
  2. Spring Boot 三大开发工具,你都用过几个?
  3. 这款IDEA插件刷爆了技术群,群友:这用起来真酸爽~
  4. 牛逼!它比传统数据库快 100-1000,真不相信?
  5. 面试遇到“一问三不知”的,真替他老东家捏把汗
  6. IT 已成为最疯狂的加班行业,没有之一
  7. 与其纠结,不如放弃!
  8. pbewithmd5anddes算法 对应.net_「AI」目标检测第一话:R-CNN和SPP-Net
  9. DevExpress DateEdit控件选择精确到秒
  10. Wannafly挑战赛25 A.因子