pyx文件 生成pyd 文件用於 cython調用


轉於:https://www.2cto.com/kf/201405/304168.html

 

1. 初衷

最近學用python,python不愧是為程序員考慮的編程語言,寫起來很快很方便,大大節省開發效率。而且,對於小規模程序,運行效率也不錯。前兩天寫了一篇博文《【總結】學用python寫程序》,大大地誇獎了python一番。不過這兩天,我就受到“詛咒”了。數據規模稍微大一點,python的執行效率的差勁就體現出來了。這兩天寫的一個程序,盡管在我所知道的范圍內,我做了python語言能做的優化,不過程序依然運行了五個小時之久。想把程序改成c++的,不過開發時間較長,而且未來可能還有改動。所以暫罷。

上網上查了查python效率的問題。一方面,網上這方面資料不是很多,例如:我們都知道stl里面set是用紅黑樹實現的,不過python的set怎么實現的,貌似網上沒有。這說明用python的人貌似都不關心效率問題。另一方面,據網上資料說,python運行效率比java還慢。我作為c++程序員從前很鄙視java的運行效率,原來python還不如java呢!不過java是虛擬機,python是解釋器,為什么python更慢呢?原因在於python更加“面向對象”,python的所有類型都是對象,連最普通的整數變量都是對象,都要在運行的時候才能夠確定類型、才能夠動態創建......這大大加重了運行時的負擔,所以運行效率才這么差。對比之下,同樣的程序用cython寫,僅僅是聲明了變量類型,運行效率就會有35%的提升。

我從前用過openmp,見從前的博文《簡單嘗試windows多線程程序》。感覺openmp是神器一個,既方便寫程序,又能利用cpu的多個核心,大大提升運行效率。問題是,python中能夠使用openmp么?答案是悲觀的。python的默認實現是cpython,也就是用c來做的實現,而c的函數大部分都不是線程安全的,為了利用這些函數實現、同時又為了運行時的線程安全,python做了GIL(Global Interpreter Lock)的限制,也就是說,同一段時間內只有一個線程才能夠訪問python解釋器。不過這也使得python上面的並發特別困難。

不過也不是一點方法都沒有,cython現在已經支持了openmp。cython是什么?和python、cpython什么關系?python是腳本語言,cpython是用c來實現的python的解釋器,cython是另外一種編程語言,介於python和c之間。實際上cython的設計初衷也是這樣,既要利用python快捷的編程速度,又要有c語言的運行效率。cython和python的一個顯著區別就是,cython的所有變量都要明確聲明變量類型——僅僅這一點,相同的程序,cython的運行效率就要比python的高35%!雖然cython是一種獨立的編程語言,不過貌似大家不用他獨立的編寫程序,而是用它來編寫python的c擴展(用c高效實現某些程序,再給python調用)。這幾天嘗試的,就是在cython上面用openmp,並寫成python的c擴展,給python調用。

 

2. 環境

windows7 + 32bit + vistual studio 2008 + python 2.7.3 + eric4,都是默認安裝路徑。

 

3. 安裝cython

官網上下載的Cython-0.20.1,從控制台上切到cython的路徑,運行setup.py就一路編譯安裝下去了,沒遇到其他問題。

在網上看到,很多人在安裝的時候遇到很多問題,基本上都是找不到c++編譯器,具體表現是提示找不到一個叫“vs....bat”的文件。解決辦法通常是安裝mingw(gcc在windows下的版本),然后修改一個.cfg文件,指定用這個編譯器來build。

windows安裝使用這些偏底層的Python擴展太不爽了,怎么徹底解決 error: Unable to find vcvarsall.bat 呢?
    1.不要按網上說的,安裝MinGW,然后在“..python安裝路徑...\Lib\distutils”下新建一個文件distutils.cfg,在這文件里面指定編譯器為mingw32
       如:
[build]
compiler=mingw32

上面這種方式有問題,我也嘗試了一下,是不報上面的那個。error: Unable to find vcvarsall.bat錯誤了 ,但是有開始報:

UnicodeDecodeError: 'utf8' codec can't decode byte 0xb0 in position 6: invalid s
tart byte

查詢一下其他博客人家是這樣說的

百度一下mingw是什么,畢竟不是GCC,又不如VC接windows的地氣,編譯出來的東西,安裝上了也有不好使的時候。
甚至我遇到MinGW還無法編譯greenlet0.4.1,導致greenlet無法源碼安裝。
MinGW經常command 'gcc' failed with exit status 1 或者error: unrecognized command line option '-mno-cygwin'。
即使編譯通過了,安裝上了,你安裝的Python標准庫不是由mingw編譯的,
你的擴展包卻是mingw編譯的,誰也不敢保證完全兼容或者說質量跟得上,
說不准一些莫名其妙的神經質錯誤。
我的安裝過程沒有遇到問題,看網上的解釋,貌似是python2.7的cpython是用vistual studio 2008來編譯的,默認找對了編譯器,所以沒問題了。總之,裝上了,沒問題。

看來還是按裝VS2010:

摘抄於:http://blog.csdn.net/darren2015zdc/article/details/54574868    
1.去下載安裝VS2010(08版貌似也行,不過沒必要用舊版,指不定哪個庫又無法編譯),給個地址(百度的雲盤 國內應該速度可以) http://pan.baidu.com/share/link?shareid=1609273194&uk=3255422755 然后注意這一步很重要:命令行下執行 SET VS90COMNTOOLS=%VS100COMNTOOLS% 如果你安裝的是 2012 版 SET VS90COMNTOOLS=%VS110COMNTOOLS% 如果你安裝的是 2013版 SET VS90COMNTOOLS=%VS120COMNTOOLS% 或者更暴力,直接配置系統環境變量 VS90COMNTOOLS指向 %VS你的版本COMNTOOLS% 你還可以更暴力,在“..python安裝路徑...\Lib\distutils目錄下有個msvc9compiler.py找到243行 toolskey = "VS%0.f0COMNTOOLS" % version 直接改為 toolskey = "VS你的版本COMNTOOLS"(這個就是為什么要配 ”VS90COMNTOOLS“ 的原因,
因為人家文件名都告訴你了是 Microsoft vc 9的compiler, 代碼都寫死了要vc9的comntools,就要找這個玩意兒,找不到不干活) 這么做的理由是Python2。
7 擴展包是可以用08版或者更高的VS編譯的,其setup.py(安裝腳本)都是去windows系統尋找08版的VS,所以設置VS90的path 如果Python版本小於2.7,強烈建議使用 VS08版,用2010或者更高可能部分擴展不好使。給個例子: http://stackoverflow.com/questions/6551724/how-do-i-point-easy-install-to-vcvarsall-bat 這個例子說明 VS2010不適合Python2.6 2.安裝VS后該重啟的重啟,clean一下之前安裝Python擴展失敗的殘留文件,然后 直接下載 pil pillow greenlet eventlet等源碼,解壓后python setup.py build發現都可以編譯了。
接下來就換成 python setup.py install安裝吧。

 

 

4. 寫pyx文件

pyx文件是python的c擴展文件,代碼要符合cython的規范,用什么編輯器寫都行。我在eric4上寫的,結果它默認用python解釋器來進行解釋,還提示有bug,“語法錯誤”。不理會他,本來cython的語法在python里面就不支持。創建TestOMP.pyx文件,並在文件中寫代碼如下:

 TestOMP.pyx

from cython.parallel import prange, parallel, threadid
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)

 


第一句引入了cython中的並行處理模塊,尤其是prange。我理解,prange就是“python 'range' of parallel version”,就是並行循環。第二句是引入了c語言中的‘printf’函數。整個文件就定義了一個Test函數。看到,每個變量在使用前都要聲明類型。在prange中,有參數‘num_threads’來設定並發數量。nogil表示‘no gil(Global Interpreter Lock)’,想要獲得並行,這個參數就要設置。在循環過程中,調用了c的庫函數printf,來打印每個整數值。

 

5. 寫setup.py文件

pyx文件是python的c擴展文件,代碼要符合cython的規范,用什么編輯器寫都行。我在eric4上寫的,結果它默認用python解釋器來進行解釋,還提示有bug,“語法錯誤”。

上面的pyx文件還僅僅是源代碼文件,要想被python調用、要想運行,僅僅寫了源代碼還是不夠的。具體來說,還要轉成.c或者.c++的文件,並且再進一步轉成.pyd文件。pyd文件才是可以直接使用的文件。為了達到上述目的,就要寫一個setup.py腳本,如下:

  setup.py

#!/usr/bin/python  
#python version: 2.7.3  
#Filename: SetupTestOMP.py  
   
# Run as:    
#    python setup.py build_ext --inplace    
     
import sys    
sys.path.insert(0, "..")    
     
from distutils.core import setup    
from distutils.extension import Extension    
from Cython.Build import cythonize    
from Cython.Distutils import build_ext  
     
# ext_module = cythonize("TestOMP.pyx")    
ext_module = Extension(  
                        "TestOMP",  
            ["TestOMP.pyx"],  
            extra_compile_args=["/openmp"],  
            extra_link_args=["/openmp"],  
            )  
     
setup(  
    cmdclass = {'build_ext': build_ext},  
        ext_modules = [ext_module],   
)  

 

這個完全是一個python腳本,可以在python解釋器下面運行。在控制台下,運行如下命令‘python setup.py build_ext --inplace’,就生成了TestOMP.pyd文件。

當然,同時還有一些雜七雜八的文件,如‘build’目錄下面的‘lib’文件。這都提示着,這是在windows vistual studio環境下。在linux+gcc環境下,就要生成.so文件了,而且“/openmp”的選項就要寫成“-fopenmp”

當然,這里的可以回遇到這樣的問題:

Traceback (most recent call last):
File "setup.py", line 13, in <module>
from Cython.Build import cythonize
ImportError: No module named 'Cython'

可以執行pip進行安裝:pip install Cython

 

6.寫TestOMP.py

文件上述兩個步驟,相當於把某個python效率瓶頸模塊(這之前需要用profile工具來定位)用效率更高的代碼寫成了python的c擴展形式,接下來,就是要在python代碼中調用他們。TestOMP.py就是這個調用的腳本,如下:

  

from TestOMP import Test   
Test()  

 

這個就很容易了,import並且調用。在控制台下,輸入“python TestOMP.py”,運行。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM