第5篇:Cython的线性表性操作

線性表是一個線性的集合,它允許用戶在任何位置插入、刪除、訪問和替換元素。

list 與 numpy.ndarray的區別

在Python中的list就是一個簡單的線性表,從細節上看,Python中的列表是由對其他對象的引用組成的連續數組。指向這個數組的指針及其長度被保存在一個列表頭結構中

numpy是Python中科學計算的核心庫。 它提供了高性能的多維數組對象和用於處理這些數組的工具。 NumPy數組是所有相同類型的值的網格,並由非負整數的元組索引。 維數是數組的等級。 數組的形狀是一個整數元組,給出沿每個維度的數組大小。

我們更在乎的是是性能,然而形而上學的結論會誤導他人:

  • 大小-Numpy數據結構佔用更少的空間 (這點是沒異議的)
  • 性能-numpy.ndarray比list更快 (是嗎?你確認?在你這麼認為理所當然地認為前,請確認的python版本和做個試驗了嗎!!)

本篇將向您展示如何使用Cython加快NumPy數組和list的處理速度。 通過在Python中明確指定變數的數據類型,Cython可以在運行時顯著提高速度。

通過Jupyter Notebook來做如下的測試,Ok,先查看一下Python和Cython的他們版本號


Python的numpy.ndarray

在過去版本的Python中用numpy作為數組類型的計算操作的性能高於list的印象,但從如下圖,僅僅50,000,000的數據量就需要10.65秒,這個結果不禁令人大跌眼鏡


Python的list

這是一個原生的python版本,同樣邏輯的演算法,原生的list測試結果是3.89秒


ss8.png

Cython的list

我們將上面的Python版本的list迴圈修改相應的Cython版本,測試結果為3.32秒


Cython的numpy

我們將上面的Python版本的numpy.ndarray迴圈修改相應的Cython版本,測試結果為3.82秒


那麼測試結果就如下圖所示:
就目前的測試效果看來Cython版本的list運行速度是最優的方案
Python 3.6.9這一版似乎在for in迴圈結構以及list的性能優化下相比以往版本下了很大苦功,這一點值得點贊的。

現在進行進入主題,我們分析一下上面numpy優化的一些細節,先前我們看到,在為所使用的變數明確定義C類型之後,Cython代碼可以非常快速地運行。 NumPy數組也是如此。 如果我們將NumPy數組保留為當前形式,其工作方式仍然按照Python工作方式完全相同,它會為數組中的每個數字創建一個對象。 為了numpy數組運行更快,我們還需要為numPy數組定義C數據類型,就像其他任何變數一樣。

numpy數組的數據類型是ndarray,代表n維數組。 如果使用關鍵字int創建整數類型的變數,則可以使用ndarray為numpy數組創建變數。 注意,必須使用numpy調用ndarray,因為ndarray在numpy內部。 因此,用於創建numpy數組變數的語法為numpy.ndarray。 下麵列出的代碼創建一個名為arr的變數,其數據類型為numpy.ndarray。

首先要注意的是,NumPy是在第二行中使用常規關鍵字import導入的。 在第三行中,您可能會注意到NumPy也使用關鍵字cimport導入。

現在可以看到Cython檔可以分為兩類:

  • 定義檔(.pxd)
  • 實現檔(.pyx)

定義檔的擴展名為.pxd,用於保存C聲明,例如要導入並在其他Cython檔中使用的數據類型。 另一個檔是擴展名為.pyx的實現檔,我們目前正在使用該檔編寫Cython代碼。 在此檔中,我們可以導入定義檔以使用其中聲明的內!
容。

下麵的代碼將寫入擴展名為.pyx的實現檔中。 cimport numpy語句在Cython中導入名為"numpy"的定義檔。 這樣做是因為Cython的"numpy"檔具有用於處理NumPy數組的數據類型。


cimport語句

第3-4行使用了兩個import語句,import numpycimport numpy

這與哪一個相關? 在這裏,我們將使用cimport numpy,而不是普通的import語句。 因為,由於我們在第11行聲明了arr的變數類型是numpy.ndarray的類型,即cdef numpy.ndarray arr,對於Cython編譯器來說,它需要導入定義該numpy.ndarray類型的pyd檔,因此就需要cimport numpy

我們驗證一下,在Python命令提示符下使用 help("Cython")函數查看Cython擴展所在的目錄,如下圖底部,我們找到對應的目錄

我們在Cython擴展的所在目錄會找到一個叫Includes的子目錄,該目錄不僅包含numpy的pxd檔,還這包含Cython集成C庫(即libc目錄)和C++庫(即libcpp目錄)的大部分標準庫定義


ss8.png

在我的電腦中,位於~/.local/lib/python3.6/site-packages/Cython/Includes/numpy這個目錄下就有關於numpy.ndarray的類定義,在Cython編程中,cimport語句就相當與C/C++編程中的include語句

Cython中numpy數組類型

除了定義變數arr數據類型之外,我們還可以定義另外兩條資訊:

  • ndarray元素的數據類型:數組元素的數據類型為int,並根據下麵的行定義。 使用cimport導入的numpy具有numpy中的每種類型相對應的類型,但末尾帶有_t。 例如,常規numpy中的int對應於Cython中的int_t。
  • 維度數:參數是ndim,它指定數組中的維數。 此處設置為1。 請注意,其默認值也是1,因此可以從我們的示例中省略。 如果使用更多尺寸,則必須指定它。

那麼第11行的arr變數聲明

cdef numpy.ndarray arr

可以定義得更為具體聲明語句

cdef numpy.ndarray[numpy.int_t,ndim=1] arr

Cython的numpy.ndarray類型聲明和函數

很遺憾的是,僅當numpy數組是函數內部的參數或函數中的局部變數(而不是腳本主體,即全局作用域)時,才可以這種方式定義numpy數組的類型。 現在,我們需要編輯先前的代碼,以將其添加到將在下一部分中創建的函數中。 現在,讓我們在定義數組之後創建它。

請注意,我們將變數arr的類型定義為numpy.ndarray,但請不要忘記這是容器的類型。 此容器具有元素,如果未指定其他元素,則將這些元素轉換為對象。 為了將這些元素強制為整數,我會將dtype參數設置為numpy.int。此處使用的numpy是使用cimport關鍵字導入的numpy。 通常,每當找到用於定義變數的關鍵字numpy時,請確保使用cimport關鍵字將其從Cython導入。

cdef numpy.ndarray[numpy.int_t,ndim=1] arr
arr=numpy.arange(maxval,dtype=numpy.int)

以下是使用cdef 函數封裝後的array_sum函數,參數的numpy.ndarray類型即 numpy.ndarray[DTYPE_t,ndim=1],如果有C基礎的同學,應該不難看出這不就是等同於C中指向數組的指針

import time
import numpy
cimport numpy

ctypedef numpy.int_t DTYPE_t

cdef array_sum(numpy.ndarray[DTYPE_t,ndim=1] arr):
    cdef int n
    cdef unsigned long long total
    cdef int k
    cdef double t1,t2
    
    t1=time.time()
    
    for k in arr:
        total=total+k
    print("total=",total)
    
    t2=time.time()
    print("耗時:{}".format(t2-t1))
#end-def

OK,我們嘗試編譯上面Cython程式,我建議使用setup.py的方式去編譯,因為我們需要將numpy的Python代碼編譯成C代碼還需要在setup.py檔中顯式設定include_dirs參數,該參數包含numpy相關的C/C++頭檔,

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

setup(
    name="array_sum",
    ext_modules=cythonize("./array.pyx"),
    include_dirs=[numpy.get_include()]
)
ss8.png

更新中.....

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容