尝试cython和openmp
最近學用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調用。
windows7 + 32bit + vistual studio 2008 + python 2.7.3 + eric4,都是默認安裝路徑。
官網上下載的Cython-0.20.1,從控制臺上切到cython的路徑,運行setup.py就一路編譯安裝下去了,沒遇到其他問題。
在網上看到,很多人在安裝的時候遇到很多問題,基本上都是找不到c++編譯器,具體表現是提示找不到一個叫“vs…bat”的文件。解決辦法通常是安裝mingw(gcc在windows下的版本),然后修改一個.cfg文件,指定用這個編譯器來build。
我的安裝過程沒有遇到問題,看網上的解釋,貌似是python2.7的cpython是用vistual studio 2008來編譯的,默認找對了編譯器,所以沒問題了。總之,裝上了,沒問題。
pyx文件是python的c擴展文件,代碼要符合cython的規范,用什么編輯器寫都行。我在eric4上寫的,結果它默認用python解釋器來進行解釋,還提示有bug,“語法錯誤”。不理會他,本來cython的語法在python里面就不支持。創建TestOMP.pyx文件,并在文件中寫代碼如下:
from cython.parallel import prange, parallel, threadid from libc.stdio cimport printfdef Test():cdef int i = 0cdef int sum = 0for 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,來打印每個整數值。
上面的pyx文件還僅僅是源代碼文件,要想被python調用、要想運行,僅僅寫了源代碼還是不夠的。具體來說,還要轉成.c或者.c++的文件,并且再進一步轉成.pyd文件。pyd文件才是可以直接使用的文件。為了達到上述目的,就要寫一個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”
上述兩個步驟,相當于把某個python效率瓶頸模塊(這之前需要用profile工具來定位)用效率更高的代碼寫成了python的c擴展形式,接下來,就是要在python代碼中調用他們。TestOMP.py就是這個調用的腳本,如下:
from TestOMP import TestTest()這個就很容易了,import并且調用。在控制臺下,輸入“python TestOMP.py”,運行。
上面是在控制臺上的輸出的一個片段。能夠看到,的確是prange把1000000這一個大循環分成了兩個區間:[0, 500000) 和 (500001,1000000],兩個循環并行運行,并交替使用控制臺IO進行輸出。
同時寫了一個對等的c++程序,如下:
同時,在Configuration Properties->C/C+±>Language->OpenMP Support,在下拉菜單里選擇Yes。并且從C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.OPENMP 和 C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugOpenMP目錄下分別拷貝vcomp90d.dll和vcomp90.dll文件到工程文件當前目錄下,或者將上述兩個路徑設置到環境變量里面。
編譯、運行,結果和python上面的一樣——不過貌似更快!
完。
轉載請注明出處:http://blog.csdn.net/xceman1997/article/details/26977483
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的尝试cython和openmp的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 微信支付md5签名,微信支付回调
- 下一篇: 创建mysql代码实例_MySQL筹建系