与“普通” Python相比,Cython为我们提供了更多对array.array内部的访问,因此我们可以利用它来加速代码:

>对于您的小示例,几乎减少了7倍(消除了大部分开销).

对于较大的输入,通过消除不必要的数组副本,将其乘以2.

请阅读以获得更多详情.

尝试针对如此小的输入优化功能是有点不寻常的,但并非没有(至少是理论上的)兴趣.

因此,让我们从您的函数作为基线开始:

a=array('l', [1,2,3])

%timeit pyappend(a, 8)

1.03 ?s ± 10.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

lst=[1,2,3]

%timeit pylistappend(lst, 8)

279 ns ± 6.03 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

我们必须意识到:我们要衡量的不是复制成本而是开销成本(python解释器,调用函数等),例如a包含3个元素还是5个元素没有什么区别:

a=array('l', range(5))

%timeit pyappend(a, 8)

1.03 ?s ± 6.76 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

在数组版本中,我们有更多的开销,因为我们通过复制模块进行了间接访问,我们可以尝试消除这种情况:

def pyappend2(arr, x):

result = array('l',arr)

result.append(x)

return result

%timeit pyappend2(a, 8)

496 ns ± 5.04 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

那更快.现在让我们使用cython-这将消除翻译程序的成本:

%%cython

def cylistappend(lst, x):

result = lst[:]

result.append(x)

return result

%%cython

from cpython cimport array

def cyappend(array.array arr, long long int x):

cdef array.array res = array.array('l', arr)

res.append(x)

return res

%timeit cylistappend(lst, 8)

193 ns ± 12.4 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%%timeit cyappend(a, 8)

421 ns ± 8.08 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

cython版本的列表大约快33%,阵列大约快10%.构造函数array.array()期望可迭代,但是我们已经有了array.array,因此我们使用cpython中的功能来访问array.array对象的内部,并稍微改善这种情况:

%%cython

from cpython cimport array

def cyappend2(array.array arr, long long int x):

cdef array.array res = array.copy(arr)

res.append(x)

return res

%timeit cyappend2(a, 8)

305 ns ± 7.25 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

下一步,我们需要知道array.array如何追加元素:通常为it over-allocates,所以append()的摊销成本为O(1),但是在array.copy之后,新数组恰好是所需数量的元素,下一个追加调用重新分配.我们需要进行更改(有关使用的功能的说明,请参见here):

%%cython

from cpython cimport array

from libc.string cimport memcpy

def cyappend3(array.array arr, long long int x):

cdef Py_ssize_t n=len(arr)

cdef array.array res = array.clone(arr,n+1,False)

memcpy(res.data.as_voidptr, arr.data.as_voidptr, 8*n)#that is pretty sloppy..

res.data.as_longlongs[n]=x

return res

%timeit cyappend3(a, 8)

154 ns ± 1.34 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

与您的函数类似,内存已过度分配,因此我们不再需要调用resize().现在我们比列表快,比原始python版本快近7倍.

让我们比较一下更大数组大小的时序(a = array(‘l’,range(1000)),lst = list(range(1000))),其中数据的复制占据了大部分运行时间:

pyappend 1.84 ?s #copy-module is slow!

pyappend2 1.02 ?s

cyappend 0.94 ?s #cython no big help - we are copying twice

cyappend2 0.90 ?s #still copying twice

cyappend3 0.43 ?s #copying only once -> twice as fast!

pylistappend 4.09 ?s # needs to increment refs of integers

cylistappend 3.85 ?s # the same as above

现在,消除不必要的array.array副本可以得到预期的因子2.

对于更大的数组(10000个元素),我们看到以下内容:

pyappend 6.9 ?s #copy-module is slow!

pyappend2 4.8 ?s

cyappend2 4.4 ?s

cyappend3 4.4 ?s

两个版本之间不再存在差异(如果放弃慢速复制模块).这样做的原因是对如此大量元素的array.array的行为发生了改变:复制时,它会过度分配,从而避免了在第一个append()之后进行重新分配.

我们可以轻松地检查它:

b=array('l', array('l', range(10**3)))#emulate our functions

b.buffer_info()

[] (94481422849232, 1000)

b.append(1)

b.buffer_info()

[] (94481422860352, 1001) # another pointer address -> reallocated

...

b=array('l', array('l', range(10**4)))

b.buffer_info()

[](94481426290064, 10000)

b.append(33)

b.buffer_info()

[](94481426290064, 10001) # the same pointer address -> no reallocation!

python创建数组并运行_python-Cython中从现有数组和变量创建新数组...相关推荐

  1. Java黑皮书课后题第7章:*7.12(倒置数组)7.7节中的reverse方法通过复制到新数组实现倒置。改写方法将参数中传递的数组倒置,并返回该数组。编写一个测试程序,输入10个数字,倒置它们并显示

    7.12(倒置数组)7.7节中的reverse方法通过复制到新数组实现倒置.改写方法将参数中传递的数组倒置,并返回该数组.编写一个测试程序,输入10个数字,倒置它们并显示 题目 题目描述 破题 代码 ...

  2. Python编程语言学习:在for循环中如何同时使用2个变量或者3个变量

    Python编程语言学习:在for循环中如何同时使用2个变量或者3个变量 目录 在for循环中如何同时使用2个变量或者3个变量 在for循环中如何同时使用2个变量

  3. 数组[Java](除去一个数组中的某个值并生成一个新数组)

    ** 数组 **[Java](除去一个数组中的某个值并生成一个新数组) 例如:现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} ; ...

  4. python启动多个进程_Python程序中的进程操作--—--开启多进程

    Python程序中的进程操作-----开启多进程 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创 ...

  5. python输入y继续运行_Python二三事 - 接触Python(x,y)

    注释:本文原来转自博客大巴的一篇文章,向原作者致谢!我也做了相应的修改,更加完善对于Pythonx,y的介绍 Python 二三事 面向初学者介绍Python相关的一些工具,以及可能遇到的常见问题. ...

  6. python类中包含一个特殊的变量、它可以访问类的成员_Python类中包含一个特殊的变量( ),它表示当前对象自身,可以访问类的成员....

    包含票务系统的业务管理主要内容包括()A:运营监督B:规则管理C:信息管理D:财务管理E:模式管理 特殊表嘌呤核苷酸补救合成途径的主要器官是().A:脑组织B:小肠C:胸腺D:肝脏E:肾脏 示当身嘌呤 ...

  7. java中字符串的创建_【转载】 Java中String类型的两种创建方式

    本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...

  8. mysql 存储过程 set into_mysql存储过程之创建(CREATE PROCEDURE)和调用(CALL)及变量创建(DECLARE)和赋值(SET)操作方法...

    本文实例讲述了mysql存储过程之创建(CREATE PROCEDURE)和调用(CALL)及变量创建(DECLARE)和赋值(SET)操作方法.分享给大家供大家参考,具体如下: 存储过程创建(CRE ...

  9. python三维数组怎么表示_python – numpy中的三维数组

    你有一个截断的数组表示.让我们看一个完整的例子: >>> a = np.zeros((2, 3, 4)) >>> a array([[[ 0., 0., 0., 0 ...

  10. python中如何创建类的对象_python面向对象中如何建立具体的对象?

    我们现在眼前所能看到的事物,都是具体的对象.很多小伙伴在面向对象中创建对象,其实都停留在对象名称的建立,计算机中并没有具体对象的描述属性.我们想要使用python中的类,建立的对象就需要是具体的.下面 ...

最新文章

  1. python中nlp的库_单词袋简介以及如何在Python for NLP中对其进行编码
  2. java.io.file()_Java IO(一):IO和File
  3. 光流(Optical Flow)简介
  4. matlab图像显示时间,请问怎么把样点数变成时间显示在图像了里
  5. 浅谈NLP中的对抗训练方式
  6. mysql逻辑备份之mysqldump
  7. 基于Dockerfile创建一个最简单的docker镜像
  8. Python -- sys模块
  9. linux系统 远程桌面连接到服务器,Ubuntu 14.04服务器远程桌面连接
  10. 解决人工智能PCA算法输出不稳定的方案
  11. SparkSQL源代码:GlobalTempView与LocalTempView
  12. 1、linux网络服务实验 用PuTTY连接Linux
  13. python小波去噪的方法_小波去噪基本概念
  14. Fedora 13 咪咕播放器
  15. 关于Pandownload一些功能的挖掘
  16. 100923G-Por Costel and the Orchard
  17. Weka中数据挖掘与机器学习系列之Exploer界面(七)
  18. 最通俗易懂---多分类学习之OvO、OvR、MvM
  19. Python爬虫(第五周)
  20. java返回一个布尔值_关于java:返回布尔值的方法

热门文章

  1. cf813C(bfs)
  2. mui dtpicker 时间的设置 以及MUI的弹窗
  3. GCD中的队列与任务
  4. 每个前端工程师都应该懂的前端性能优化总结:
  5. MATLAB半色调,基于改进协方差矩阵的半色调图像分类研究
  6. 取到小数后三位_小数名师工作室 数学实验 || 一个小数乘10、100、1000……的计算规律...
  7. java 过滤器 弹出提示_JavaWeb 过滤器——验证登录 防止未登录进入界面
  8. 最近点对模板__hdu1007
  9. Cadence 16 ( Allegro PCB ) 使用 Shape Symbol 制作不规则焊盘
  10. 图论算法在机试实现中的一些技巧和陷阱