高性能Python:使用Cython

2021-03-02 編程派

編程派微信號:codingpy

準確的說,Cython是單獨的一門語言,專門用來寫在Python裡面import用的擴展庫。實際上Cython的語法基本上跟Python一致,而Cython有專門的「編譯器」;先將 Cython代碼轉變成C(自動加入了一大堆的C-Python API),然後使用C編譯器編譯出最終的Python可調用的模塊。

本文分享自:http://blog.soliloquize.org/

Cython安裝

Cython可以通過pip直接進行安裝,

pip install cython

Cython代碼編譯與使用

以一個簡短的代碼樣例來看下Cython如何使用,

定義一個.pyx文件,

import math
def pythagorean(a, b):  return math.sqrt(a**2 + b**2)

使用disutils、cythonize

定義setup.py腳本,

from distutils.core import setup
from Cython.Build import cythonizesetup(  ext_modules = cythonize('foo.pyx'),)

在命令行中運行,

python setup.py build_ext --inplace

進入Python命令行,

>>> import foo
>>> foo.pythagorean(3, 4)5.0

使用pyximport

在開發調試階段為了簡化操作可以使用Cython中定義的pyximport來直接從.pyx文件加載模塊,

進入Python命令行,

>>> import pyximport
>>> pyximport.install()(None, <pyximport.pyximport.PyxImporter object at 0x026F6C30>)
>>> import foo
>>> foo.pythagorean(3, 4)5.0

性能比較

使用Cython的目的是為了提升性能,因此需要來實際檢驗一下,擴展foo.pyx增加兩個函數,

import math

def pythagorean(a, b):    return math.sqrt(a**2 + b**2)

def fibonacci(n):    if n <= 0 or n == 1:
       return 1    a = 1    b = 1    for i in xrange(n - 1):        c = a + b        a = b        b = c
   return c

def factor(n):    if n <= 1:
       return 1    return n * factor(n - 1)

這三個函數中pythagorean是簡單的小函數,fibonacci存在循環,factor存在遞歸。純Python代碼可以直接用Cython進行編譯,因此先來看一下在代碼不變的情況下使用Cython會有怎樣的性能變化。

用ipython可以方便的來進行對比,

pip install ipython

在ipython中使用timeit來進行度量,

In [6]: %timeit pythagorean(3, 4)The slowest run took 14.37 times longer than the fastest. This could mean that an intermediate result is being cached.1000000 loops, best of 3: 290 ns per loopIn [7]: %timeit foo.pythagorean(3, 4)The slowest run took 15.36 times longer than the fastest. This could mean that an intermediate result is being cached.1000000 loops, best of 3: 292 ns per loopIn [8]: %timeit fibonacci(100)
100000 loops, best of 3: 8.84 µs per loopIn [9]: %timeit foo.fibonacci(100)
100000 loops, best of 3: 5.11 µs per loopIn [12]: %timeit factor(20)
100000 loops, best of 3: 3.6 µs per loopIn [13]: %timeit foo.factor(20)
100000 loops, best of 3: 2.41 µs per loop

上面三組對比可以看到,在Python腳本代碼不發生改變情況下,將其用Cython進行編譯。如果代碼中存在較多的循環或函數調用,那麼能夠獲得一定的性能提升,但如果代碼本身很精簡,則性能不會有提升,甚至還是Python版本快。

類型信息描述

想要獲得更多的性能提升,需要讓Cython知道更多信息。靜態信息越多,Cython能夠獲取到的性能提升也就越多,

cpdef int fibonacci(int n):    cdef int i, a, b, c
   if n <= 0 or n == 1:
       return 1    a = 1    b = 1    for i in xrange(n - 1):        c = a + b        a = b        b = c
   return ccpdef long long factor(int n):
   if n <= 1:
       return 1    return n * factor(n - 1)

將foo.pyx中的代碼做少許修改,增加函數參數、返回值等類型信息,再來看下性能變化,

In [21]: %timeit fibonacci(100)
100000 loops, best of 3: 7.42 µs per loopIn [22]: %timeit foo.fibonacci(100)
100000 loops, best of 3: 4.62 µs per loopIn [26]: %timeit factor(20)
100000 loops, best of 3: 5.83 µs per loopIn [27]: %timeit foo.factor(20)
100000 loops, best of 3: 2.22 µs per loop

可以看到,在提供了類型信息之後,性能提升幅度增大了不少。在這幾個樣例中,能進一步提升的餘地不多了。但一個利好的結論是Cython能夠在對Python代碼進行少量修改的情況下,獲得幅度客觀的性能提升。這種改動甚至不需要對Cython有太深入的了解。

總結

從使用者的需求來說,Python代碼面臨性能問題尋求優化時,Cython是其中一個選項。從以上代碼片段來看,Cython使用上算方便,在不對代碼進行大改的情況下可以獲得一定的性能提升。但同樣的,引入Cython也意味著引入了額外的複雜性。最終是否選擇它,還是需要進一步評估其帶來的收益,畢竟也可以看到並不是什麼代碼都能通過它獲得高性能增長的。

參考

相關焦點

  • cython初體驗
    本文是筆者第一次使用cython的一個小結筆者最近參與了一個項目,其目的是提升一個python程序的運行速度。其中一個手段就是利用cython來優化原來的python代碼。筆者之前沒有接觸過cython,所以這次屬於在實踐中學習新知識。
  • Python代碼加速利器:Cython
    對於Linux,通常使用GNU C編譯器(gncc)。對於Mac OS,您可以下載Xcode以獲取gncc。而Windows 桌面系統下安裝C編譯器會更複雜。有了C編譯器之後,你只需運行:如何使用Cython我們將在IPython中演示Cython。我們首先介紹IPython Magic命令。
  • 10分鐘入門Cython
    www.zhihu.com/people/li_xiaowen/activities作者其他好文傳送門:協同過濾(ALS)的原理及Python實現回歸樹的原理及Python實現本文github:https://github.com/tushushu/flying-python
  • 如何壓榨Cython及OpenMP優化Target Encoding
    最重要的一點就是我們需要先優化python代碼(算法複雜度),再去用cython(底層),最後才用並行(多線程多進程),不能本末倒置。首先需要使用notebook的cython前需要加載cython然後在在每個代碼欄前加上%%cython,cython使用cdef來定義c變量和c函數,例如%%cython
  • 量化交易之《Python數據分析》
    Numpy:提供數值數組和函數Scipy:科學計算庫Matplotlib:數據可視化 Numpy 數組的優勢1 Numpy數組能夠運用向量化運算來處理整個數組,而完成同樣的任務,python的列表則通常必須藉助循環語句遍歷列表,並對逐個元素進行相應的處理2 Numpy使用了優化過的C
  • Python 性能優化
    方式很多:到處加log列印時間戳、或者將懷疑的函數使用timeit進行單獨測試,但最有效的是使用profile工具。python profilers對於python程序,比較出名的profile工具有三個:profile、cprofile和hotshot。
  • Cython 0.20 發布,Python 的 C 語言擴展
    實際上Cython的語法基本上跟Python一致,而Cython有專門的「編譯器」先將 Cython代碼轉變成C(自動加入了一大堆的C-Python API),然後使用C編譯器編譯出最終的Python可調用的模塊。Cython 0.20 發布了,詳細改進記錄如下:Support for CPython 3.4.
  • Python日課-2.5-python語言的不同實現
    曾老師的 Python 課(連結可點擊) 第一課的所有內容已經全部發布,包括課程 PPT、課程視頻都可以免費獲取,可以使用微信掃描下面的二維碼進群獲取
  • 如何讓Python腳本變成Windows應用
    編譯pyqt5腳本為gui 程序需求有一個數據處理的腳本,需要對輸入的excel文件進行少許處理後從長ID轉成寬ID後再保存,用pandas很容易解決這個需求但是要打包成exe文在windows下使用。
  • 如何在python中引入高性能數據類型?
    作者|skura 來源|AI開發者 python 就像一件藝術珍藏品!python 最大的優點之一是它可以廣泛地選擇模塊和包。它們將 python 的功能擴展到許多流行的領域,包括機器學習、數據科學、web 開發、前端等等。其中最好的一個優點是 python 的內置 collections 模塊。
  • 讓Python代碼更快運行的 5 種方法
    相關連結:https://github.com/dropbox/pystonNuitkaNuitka 是一個Python的替代品,一些團隊正用它做完全的Python編譯工具,並嘗試將Python代碼轉譯為其它可高速運行的程式語言。
  • 快100 倍,Python 為自然語言處理加速度!
    一個辦法是使用cProfile(https://docs.python.org/3/library/profile.html):import cProfileimport pstatsimport my_slow_modulecProfile.run('my_slow_module.run()'
  • Numba:基於CUDA加速的高性能Python
    導致python如此流行的原因有很多,主要有其簡潔且易於理解的語法和標準的數據結構,廣泛的功能齊備的標準庫,優秀的文檔,庫和工具構成的良好的生態系統,專業支持的可用性以及大而開放的社區。也許最重要的是,像Python這樣的動態類型解釋語言的高效率。Python是靈活的,這使其成為可用於快速原型設計的一種很好的語言,同時也能用於構建完整的系統。
  • 快 100 倍,Python 為自然語言處理加速度!
    一個辦法是使用cProfile(https://docs.python.org/3/library/profile.html):import cProfileimport pstatsimport my_slow_modulecProfile.run('my_slow_module.run()', 'restats')p = pstats.Stats
  • 微軟發布新的VS Code Python語言插件Pylance:高性能代碼提示
    Pylance依賴於微軟官方的ms-python,目前在VS Code應用市場可以下載。本文蟲蟲就帶大家一起嘗鮮使用這個插件。概述Pylance是對Python語言的新的伺服器,使用語言伺服器協議和VS Code進行通信。
  • Numba:用CUDA加速的高性能Python編譯器
    使python如此受歡迎的因素有很多,包括其乾淨的、表達性的語法和標準的數據結構,綜合的「內置電池」標準庫,優秀的文檔,庫和工具的廣泛生態系統,專業支持的可用性,以及大而開放的社區。不過,也許最重要的原因是,像Python這樣的動態類型化的解釋語言能夠提高生產率。Python足夠敏捷與靈活,使它成為快速原型開發的一種偉大語言,同時也是構建完整系統的語言。
  • 這個加速包讓Python代碼飛起來
    其實有很多可以提高運行速度的辦法,比如: 利用多進程庫來使用所有的CPU內核; 如果你正在使用NumPy,Pandas,或是Scikit-Learn庫,那麼可以使用Rapids來提高GPU的處理速度。
  • 四種高性能數據類型,Python collections助你優化代碼、簡潔任務
    collections 模塊提供了額外的高性能數據類型,它們可以優化代碼,讓一些任務變得更加簡潔。本文作者 George Seif(機器學習工程師)。defaultdict官方文檔:https://docs.python.org/2/library/collections.html#collections.defaultdictdefaultdict 的工作方式和平常的 python dictionary 完全相同,只是當你試圖訪問一個不存在的鍵時,它不會報錯,而是會使用默認值初始化這個鍵。
  • Why Python is Slow? Looking Under the Hood
    前言最近寫了點rankboost相關的代碼,發現當weaklearner比較多且數據量巨大的時候,單純的利用python+sklearn+numpy來fit是非常慢的,就想到了之前用過的cython,寫完之後果然效率飛起啊。但是為什麼python如此之慢呢?我這個菜雞還是需要學習一下的。。。Why python is slow?
  • 《概率深度學習:使用Python,Keras和TensorFlow概率》附下載
    Probabilistic Deep Learning: With Python, Keras and TensorFlow Probability作者: Oliver Duerr出版日期: 2020ISBN: 9781617296079頁數: 252語言: English格式: PDF大小: 60 Mb概率性深度學習: 使用