详解如何利用Cython为Python代码加速


Posted in Python onJanuary 27, 2018

引言

通常,在 Python 中写循环(特别是多重循环)非常的慢,在文章 https://3water.com/article/133807.htm中,我们的元胞自动机的状态更新函数 update_state 使用了两重循环,所以我们尝试用 Cython 重构该方法。

代码

我们在同文件夹下新建一个 update.pyx 文件,写入如下内容

import numpy as np 
cimport numpy as np 
cimport cython


DTYPE = np.float
ctypedef np.float_t DTYPE_t

def update_state(np.ndarray[DTYPE_t, ndim=2] cells):
  return update_state_c(cells)

@cython.boundscheck(False)
@cython.wraparound(False)
cdef np.ndarray[DTYPE_t, ndim=2] update_state_c(np.ndarray[DTYPE_t, ndim=2] cells):
  """更新一次状态"""
  cdef unsigned int i
  cdef unsigned int j

  cdef np.ndarray[DTYPE_t, ndim=2] buf = np.zeros((cells.shape[0], cells.shape[1]), dtype=DTYPE)
  cdef DTYPE_t neighbor_num
  for i in range(1, cells.shape[0] - 1):
    for j in range(1, cells.shape[0] - 1):
      # 计算该细胞周围的存活细胞数
      
      neighbor_num = cells[i, j-1] + cells[i, j+1] + cells[i+1, j] + cells[i-1, j] +\
              cells[i-1, j-1] + cells[i-1, j+1] +\
              cells[i+1, j-1] + cells[i+1, j+1]
      
      if neighbor_num == 3:
        buf[i, j] = 1
      elif neighbor_num == 2:
        buf[i, j] = cells[i, j]
      else:
        buf[i, j] = 0
  return buf

update_state_c 函数上的两个装饰器是用来关闭 Cython 的边界检查的。

在同文件下新建一个 setup.py 文件

import numpy as np
from distutils.core import setup
from Cython.Build import cythonize

setup(
  name="Cython Update State",
  ext_modules=cythonize("update.pyx"),
  include_dirs=[np.get_include()]
)

因为在 Cython 文件中使用了 NumPy 的头文件,所以我们需要在 setup.py 将其包含进去。

执行 python setup.py build_ext --inplace 后,同文件夹下会生成一个 update.cp36-win_amd64.pyd 的文件,这就是编译好的 C 扩展。

我们修改原始的代码,首先在文件头部加入 import update as cupdate,然后修改更新方法如下

def update_state(self):
  """更新一次状态"""
  self.cells = cupdate.update_state(self.cells)
  self.timer += 1

将原方法名就改为 update_state_py 即可,运行脚本,无异常。

测速

我们编写一个方法来测试一下使用 Cython 可以带来多少速度的提升

def test_time():
  import time
  game = GameOfLife(cells_shape=(60, 60))
  t1 = time.time()
  for _ in range(300):
    game.update_state()
  t2 = time.time()
  print("Cython Use Time:", t2 - t1)
  del game
  game = GameOfLife(cells_shape=(60, 60))
  t1 = time.time()
  for _ in range(300):
    game.update_state_py()
  t2 = time.time()
  print("Native Python Use Time:", t2 - t1)

运行该方法,在我的电脑上输出如下

Cython Use Time: 0.007000446319580078
Native Python Use Time: 4.342248439788818

速度提升了 600 多倍。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python使用py2exe打包程序介绍
Nov 20 Python
Python中使用MELIAE分析程序内存占用实例
Feb 18 Python
Python中使用PyQt把网页转换成PDF操作代码实例
Apr 23 Python
Python实现PS图像抽象画风效果的方法
Jan 23 Python
Python yield与实现方法代码分析
Feb 06 Python
Tensorflow之Saver的用法详解
Apr 23 Python
python os.path模块常用方法实例详解
Sep 16 Python
python画图系列之个性化显示x轴区段文字的实例
Dec 13 Python
python中tab键是什么意思
Jun 18 Python
PyTorch实现重写/改写Dataset并载入Dataloader
Jul 14 Python
python常量折叠基础知识点讲解
Feb 28 Python
Python 居然可以在 Excel 中画画你知道吗
Feb 15 Python
详解Python 实现元胞自动机中的生命游戏(Game of life)
Jan 27 #Python
Python实现的栈(Stack)
Jan 26 #Python
使用python实现链表操作
Jan 26 #Python
Python中optparser库用法实例详解
Jan 26 #Python
python利用socketserver实现并发套接字功能
Jan 26 #Python
Django的HttpRequest和HttpResponse对象详解
Jan 26 #Python
Python编程实现的简单神经网络算法示例
Jan 26 #Python
You might like
使用PHP模拟HTTP认证
2006/10/09 PHP
ThinkPHP表单自动提交验证实例教程
2014/07/18 PHP
PHP中单引号与双引号的区别分析
2014/08/19 PHP
PHP空值检测函数与方法汇总
2017/11/19 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
php使用yield对性能提升的测试实例分析
2019/09/19 PHP
用JQuery调用Session的实现代码
2010/10/29 Javascript
firefox下input type="file"的size是多大
2011/10/24 Javascript
ASP.NET jQuery 实例8 (动态添加内容到DropDownList)
2012/02/03 Javascript
JavaScript的事件绑定(方便不支持js的时候)
2013/10/01 Javascript
js导出table数据到excel即导出为EXCEL文档的方法
2013/10/10 Javascript
jquery中each方法示例和常用选择器
2014/07/08 Javascript
浅谈document.write()输出样式
2015/05/07 Javascript
JS实现的验证身份证及获取地区功能示例
2017/01/16 Javascript
Vue实例简单方法介绍
2017/01/20 Javascript
jquery请求servlet实现ajax异步请求的示例
2017/06/03 jQuery
ReactNative短信验证码倒计时控件的实现代码
2017/07/20 Javascript
vue+element-ui动态生成多级表头的方法
2018/08/28 Javascript
vue.js表单验证插件(vee-validate)的使用教程详解
2019/05/23 Javascript
Vue 封装防刷新考试倒计时组件的实现
2020/06/05 Javascript
JS实现audio音频剪裁剪切复制播放与上传(步骤详解)
2020/07/28 Javascript
[05:56]第十六期——新进3大C之小兔基
2014/06/24 DOTA
python生成密码字典的方法
2018/07/06 Python
python绘制热力图heatmap
2020/03/23 Python
python引用(import)某个模块提示没找到对应模块的解决方法
2019/01/19 Python
python flask框架实现重定向功能示例
2019/07/02 Python
解决Tensorflow sess.run导致的内存溢出问题
2020/02/05 Python
PyQt5中QSpinBox计数器的实现
2021/01/18 Python
python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析
2021/02/20 Python
Get The Label中文官网:英国运动时尚购物平台
2017/04/19 全球购物
大学生毕业求职自荐书范文
2014/02/04 职场文书
生日主持词
2014/03/20 职场文书
运动会标语
2014/06/21 职场文书
小区门卫岗位职责范本
2014/08/24 职场文书
年中了,该如何写好个人述职报告?
2019/07/02 职场文书
Element实现动态表格的示例代码
2021/08/02 Javascript