尝试cython和openmp
最近學(xué)用python,python不愧是為程序員考慮的編程語(yǔ)言,寫起來(lái)很快很方便,大大節(jié)省開(kāi)發(fā)效率。而且,對(duì)于小規(guī)模程序,運(yùn)行效率也不錯(cuò)。前兩天寫了一篇博文《【總結(jié)】學(xué)用python寫程序》,大大地夸獎(jiǎng)了python一番。不過(guò)這兩天,我就受到“詛咒”了。數(shù)據(jù)規(guī)模稍微大一點(diǎn),python的執(zhí)行效率的差勁就體現(xiàn)出來(lái)了。這兩天寫的一個(gè)程序,盡管在我所知道的范圍內(nèi),我做了python語(yǔ)言能做的優(yōu)化,不過(guò)程序依然運(yùn)行了五個(gè)小時(shí)之久。想把程序改成c++的,不過(guò)開(kāi)發(fā)時(shí)間較長(zhǎng),而且未來(lái)可能還有改動(dòng)。所以暫罷。
上網(wǎng)上查了查python效率的問(wèn)題。一方面,網(wǎng)上這方面資料不是很多,例如:我們都知道stl里面set是用紅黑樹(shù)實(shí)現(xiàn)的,不過(guò)python的set怎么實(shí)現(xiàn)的,貌似網(wǎng)上沒(méi)有。這說(shuō)明用python的人貌似都不關(guān)心效率問(wèn)題。另一方面,據(jù)網(wǎng)上資料說(shuō),python運(yùn)行效率比java還慢。我作為c++程序員從前很鄙視java的運(yùn)行效率,原來(lái)python還不如java呢!不過(guò)java是虛擬機(jī),python是解釋器,為什么python更慢呢?原因在于python更加“面向?qū)ο蟆?#xff0c;python的所有類型都是對(duì)象,連最普通的整數(shù)變量都是對(duì)象,都要在運(yùn)行的時(shí)候才能夠確定類型、才能夠動(dòng)態(tài)創(chuàng)建…這大大加重了運(yùn)行時(shí)的負(fù)擔(dān),所以運(yùn)行效率才這么差。對(duì)比之下,同樣的程序用cython寫,僅僅是聲明了變量類型,運(yùn)行效率就會(huì)有35%的提升。
我從前用過(guò)openmp,見(jiàn)從前的博文《簡(jiǎn)單嘗試windows多線程程序》。感覺(jué)openmp是神器一個(gè),既方便寫程序,又能利用cpu的多個(gè)核心,大大提升運(yùn)行效率。問(wèn)題是,python中能夠使用openmp么?答案是悲觀的。python的默認(rèn)實(shí)現(xiàn)是cpython,也就是用c來(lái)做的實(shí)現(xiàn),而c的函數(shù)大部分都不是線程安全的,為了利用這些函數(shù)實(shí)現(xiàn)、同時(shí)又為了運(yùn)行時(shí)的線程安全,python做了GIL(Global Interpreter Lock)的限制,也就是說(shuō),同一段時(shí)間內(nèi)只有一個(gè)線程才能夠訪問(wèn)python解釋器。不過(guò)這也使得python上面的并發(fā)特別困難。
不過(guò)也不是一點(diǎn)方法都沒(méi)有,cython現(xiàn)在已經(jīng)支持了openmp。cython是什么?和python、cpython什么關(guān)系?python是腳本語(yǔ)言,cpython是用c來(lái)實(shí)現(xiàn)的python的解釋器,cython是另外一種編程語(yǔ)言,介于python和c之間。實(shí)際上cython的設(shè)計(jì)初衷也是這樣,既要利用python快捷的編程速度,又要有c語(yǔ)言的運(yùn)行效率。cython和python的一個(gè)顯著區(qū)別就是,cython的所有變量都要明確聲明變量類型——僅僅這一點(diǎn),相同的程序,cython的運(yùn)行效率就要比python的高35%!雖然cython是一種獨(dú)立的編程語(yǔ)言,不過(guò)貌似大家不用他獨(dú)立的編寫程序,而是用它來(lái)編寫python的c擴(kuò)展(用c高效實(shí)現(xiàn)某些程序,再給python調(diào)用)。這幾天嘗試的,就是在cython上面用openmp,并寫成python的c擴(kuò)展,給python調(diào)用。
windows7 + 32bit + vistual studio 2008 + python 2.7.3 + eric4,都是默認(rèn)安裝路徑。
官網(wǎng)上下載的Cython-0.20.1,從控制臺(tái)上切到cython的路徑,運(yùn)行setup.py就一路編譯安裝下去了,沒(méi)遇到其他問(wèn)題。
在網(wǎng)上看到,很多人在安裝的時(shí)候遇到很多問(wèn)題,基本上都是找不到c++編譯器,具體表現(xiàn)是提示找不到一個(gè)叫“vs…bat”的文件。解決辦法通常是安裝mingw(gcc在windows下的版本),然后修改一個(gè).cfg文件,指定用這個(gè)編譯器來(lái)build。
我的安裝過(guò)程沒(méi)有遇到問(wèn)題,看網(wǎng)上的解釋,貌似是python2.7的cpython是用vistual studio 2008來(lái)編譯的,默認(rèn)找對(duì)了編譯器,所以沒(méi)問(wèn)題了。總之,裝上了,沒(méi)問(wèn)題。
pyx文件是python的c擴(kuò)展文件,代碼要符合cython的規(guī)范,用什么編輯器寫都行。我在eric4上寫的,結(jié)果它默認(rèn)用python解釋器來(lái)進(jìn)行解釋,還提示有bug,“語(yǔ)法錯(cuò)誤”。不理會(huì)他,本來(lái)cython的語(yǔ)法在python里面就不支持。創(chuàng)建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”,就是并行循環(huán)。第二句是引入了c語(yǔ)言中的‘printf’函數(shù)。整個(gè)文件就定義了一個(gè)Test函數(shù)。看到,每個(gè)變量在使用前都要聲明類型。在prange中,有參數(shù)‘num_threads’來(lái)設(shè)定并發(fā)數(shù)量。nogil表示‘no gil(Global Interpreter Lock)’,想要獲得并行,這個(gè)參數(shù)就要設(shè)置。在循環(huán)過(guò)程中,調(diào)用了c的庫(kù)函數(shù)printf,來(lái)打印每個(gè)整數(shù)值。
上面的pyx文件還僅僅是源代碼文件,要想被python調(diào)用、要想運(yùn)行,僅僅寫了源代碼還是不夠的。具體來(lái)說(shuō),還要轉(zhuǎn)成.c或者.c++的文件,并且再進(jìn)一步轉(zhuǎn)成.pyd文件。pyd文件才是可以直接使用的文件。為了達(dá)到上述目的,就要寫一個(gè)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], )這個(gè)完全是一個(gè)python腳本,可以在python解釋器下面運(yùn)行。在控制臺(tái)下,運(yùn)行如下命令‘python setup.py build_ext --inplace’,就生成了TestOMP.pyd文件。當(dāng)然,同時(shí)還有一些雜七雜八的文件,如‘build’目錄下面的‘lib’文件。這都提示著,這是在windows vistual studio環(huán)境下。在linux+gcc環(huán)境下,就要生成.so文件了,而且“/openmp”的選項(xiàng)就要寫成“-fopenmp”
上述兩個(gè)步驟,相當(dāng)于把某個(gè)python效率瓶頸模塊(這之前需要用profile工具來(lái)定位)用效率更高的代碼寫成了python的c擴(kuò)展形式,接下來(lái),就是要在python代碼中調(diào)用他們。TestOMP.py就是這個(gè)調(diào)用的腳本,如下:
from TestOMP import TestTest()這個(gè)就很容易了,import并且調(diào)用。在控制臺(tái)下,輸入“python TestOMP.py”,運(yùn)行。
上面是在控制臺(tái)上的輸出的一個(gè)片段。能夠看到,的確是prange把1000000這一個(gè)大循環(huán)分成了兩個(gè)區(qū)間:[0, 500000) 和 (500001,1000000],兩個(gè)循環(huán)并行運(yùn)行,并交替使用控制臺(tái)IO進(jìn)行輸出。
同時(shí)寫了一個(gè)對(duì)等的c++程序,如下:
同時(shí),在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文件到工程文件當(dāng)前目錄下,或者將上述兩個(gè)路徑設(shè)置到環(huán)境變量里面。
編譯、運(yùn)行,結(jié)果和python上面的一樣——不過(guò)貌似更快!
完。
轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/xceman1997/article/details/26977483
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!總結(jié)
以上是生活随笔為你收集整理的尝试cython和openmp的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: php 微信支付md5签名,微信支付回调
- 下一篇: 华农java答案_华南农业大学JAVA程