Python 開發效率高,但執行速度慢(慢於 Java)。近期一個數據處理腳本經優化仍需 5 小時。重寫 C++ 成本高且後期維護難。尋找「開發效率與運行性能平衡點」:Cython + OpenMP。
from cython.parallel import prange, parallel
from libc.stdio cimport printf
def test():
cdef int i = 0
cdef int sum = 0
for i in prange(1000000, num_threads=2, nogil=True):
printf("%d\n", i)
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext = Extension(
"test_omp",
["test_omp.pyx"],
extra_compile_args=["/openmp"], # MSVC 選項
extra_link_args=["/openmp"]
)
setup(cmdclass={'build_ext': build_ext}, ext_modules=[ext])
python setup.py build_ext --inplace
產出 `test_omp.pyd`(Windows 動態庫),可直接 `import`。
from test_omp import test test()
輸出顯示兩線程交替打印,驗證並行生效。
#include <omp.h>
void PlayOMP() {
#pragma omp parallel for num_threads(2)
for (int i=0; i<1000000; ++i)
cout << i << "\n";
}
VS2008 專案屬性啟用 OpenMP,複製 `vcomp90.dll` 到輸出目錄。運行速度更快(無 Python 呼叫開銷)。
| 問題 | 解決 |
|---|---|
| 找不到 `vcvarsall.bat` | 安裝匹配 Python 版本的 VS(2.7 對應 VS2008),或配置 MinGW 修改 `distutils.cfg` |
| GIL 未釋放 | `prange` 必須加 `nogil=True`,且循環體無 Python 對象操作 |
| Linux 下編譯選項 | `extra_compile_args=["-fopenmp"]`, `extra_link_args=["-fopenmp"]` |
Cython + OpenMP 為 Python 性能瓶頸提供了低遷移成本、高並行收益的解決方案:核心熱點模塊用 Cython 重寫(加類型、釋放 GIL、OpenMP 並行),其餘業務邏輯保持 Python。適合「性能敏感但需快速迭代」的工程場景。