Python

Windows 使用 Cython 加速 Python 程式執行速度教學

介紹如何安裝與使用 Cython,結合 Python 與 C 語言的優點,提升程式的執行速度。

安裝 Cython

打開 Windows 的命令提示字元,使用 pip 安裝 cython 套件:

pip 安裝 cython

這樣就完成 Cython 的安裝了,不過由於 Cython 需要使用 C/C++ 編譯器,光只有安裝 Cython 是不夠的,必須另外安裝 Visual Studio 2019 才能使用。

安裝 Visual Studio 2019

Visual Studio 的網站下載 Visual Studio 2019 來安裝,個人使用的話下載免費的 Community 版本即可。

Visual Studio 2019

由於 Cython 只需要用到 Visual Studio 裡面的 C++建置工具,所以如果沒有用到整個 Visual Studio 的人,可以只下載 Build Tools for Visual Studio 2019 來安裝即可,這樣會省下很多硬碟空間。

Build Tools for Visual Studio 2019

以下是 Build Tools for Visual Studio 2019 的安裝步驟。
Step 1
實際安裝前,會先下載安裝程式。

Visual Studio Installer

Step 2
只需要選擇左上角的「C++ 建置工具」,其他的原件就不用安裝了。

安裝 C++ 建置工具

Step 3
等待下載與安裝過程,跑完之後就完成安裝了。

Visual Studio Installer

Hello World

Cython 可以接受幾乎任何的 Python 程式碼,將其編譯成 C 的擴充模組,以提升執行速度,以下是將普通的 Python 程式碼以 Cython 編譯成擴充模組後,在一般的 Python 程式中引入執行的步驟。
Step 1
這一行是一般 Python 的 Hello World 程式碼:

print("Hello World")

將這一行程式碼儲存成 hello.pyx

Step 2
建立一個 Python 指令稿 setup.py,內容如下:

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

setup(
    ext_modules = cythonize("hello.pyx")
)

Step 3
建立一個工作目錄,把 hello.pyxsetup.py 兩個檔案放在此目錄下:

工作目錄

Step 4
開啟 Windows 的命令提示字元,切換至工作目錄,然後執行以下指令進行編譯:

python setup.py build_ext --inplace
用 Cython 編譯

執行完成後,應該會看到「已完成程式碼產生」的訊息,這樣就代表成功編譯完成了。

用 Cython 編譯

編譯完成之後,目錄中會產生許多檔案,其中 hello.cp37-win32.pyd 這個檔案就是實際執行時所需要的擴充套件檔(動態連結檔),而其餘的檔案都是編譯過程中產生的暫存檔。

工作目錄

Step 5
有了 hello.cp37-win32.pyd 這個擴充套件檔之後,就可以在一般的 Python 程式中以 import 的方式來引入執行:

import hello
引入執行擴充模組

以上是使用 Cython 編譯一般 Python 程式碼的步驟,但是由於這個例子很簡單,看不出 Cython 的效能優勢,要在計算量較大時使用 Cython 才會比較有效益。

搜尋質數範例

這一段 Python 程式碼是用來搜尋質數的函數,我們將示範如何使用 Cython 來加速運算速度,首先將這段程式碼儲存為 primes.pyprimes_cython.pyx 兩個檔案,兩個內容完全相同。

def find(nb_primes):
    p = []
    n = 2
    while len(p) < nb_primes:
        # 檢查 n 是否為質數
        for i in p:
            if n % i == 0:
                break

        # 若是質數,則放進 p
        else:
            p.append(n)
        n += 1
    return p

接著編寫 setup.py 指令稿:

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

setup(
    ext_modules = cythonize("primes_cython.pyx")
)

在 Windows 的命令提示字元中進行編譯:

python setup.py build_ext --inplace

建立一個測試用的 Python 指令稿 run.py,內容如下:

import primes
import primes_cython
import time

start = time.time()
p1 = primes.find(10000)
print('Python: %.2f sec' % (time.time() - start))

start = time.time()
p2 = primes_cython.find(10000)
print('Cython: %.2f sec' % (time.time() - start))

這段測試指令稿可用來比較普通 Python 與 Cython 的執行時間差異。

Python: 9.13 sec
Cython: 5.63 sec

指定變數型態

上面的質數範例中,我們只使用 Cython 進行編譯,並未修改原來的 Python 程式碼,所以加速並不是很明顯,如果想要獲得更好的效能,可以稍微更改一下程式碼,指定變數的類型,這樣加速的效果會更好。

我們將上面的程式碼修改一下,使用 cdef 指定變數型態後(用法請參考 Cython 官方文件),會變成這樣:

def find(nb_primes):
    # 以 cdef 指定變數型態
    cdef list p = []
    cdef unsigned int n = 2
    cdef unsigned int i
    while len(p) < nb_primes:
        for i in p:
            if n % i == 0:
                break

        else:
            p.append(n)
        n += 1
    return p

將這段程式碼儲存為 primes_cython2.pyx,使用 Cython 編譯的過程都一樣。然後在 run.py 中加入新的測試程式碼:

import primes
import primes_cython
import primes_cython2
import time

start = time.time()
p1 = primes.find(10000)
print('Python: %.2f sec' % (time.time() - start))

start = time.time()
p2 = primes_cython.find(10000)
print('Cython: %.2f sec' % (time.time() - start))

start = time.time()
p2 = primes_cython2.find(10000)
print('Cython2: %.2f sec' % (time.time() - start))
Python: 9.72 sec
Cython: 5.72 sec
Cython2: 0.37 sec

結果非常驚人,執行時間從原本的 9 秒縮短至 0.3 秒。

常見問題

如果在編譯 *.pyx 檔案時,出現這樣的錯誤:

error: Unable to find vcvarsall.bat

就代表 Cython 找不到編譯器,要安裝 Visual Studio 2019 或是 Build Tools for Visual Studio 2019。

參考資料:賈維斯的智慧工坊Cython 官方文件

Share
Published by
Office Guide

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago