這篇文章主要介紹PyCharm跟Cython
先寫下我的檔案架構
1 2 3 4 5 6 7 8 . +-- main.py +-- fib | +-- __init__.py | +-- cfib.c | +-- cfib.h | +-- fib.pyx | +-- setup.py
每一個檔案的用途:
main.py
是主程式
__init__.py
是套件引用檔案
cfib.c
是用c寫成的fib
函數
cfib.h
是cfib的header檔,供fib.pyx
參照
fib.pyx
是Cython檔
setup.py
則是拿來編譯整個Cython的
cfib.c
內容如下:
1 2 3 4 5 6 7 8 9 #include "cfib.h" unsigned long fib (unsigned long n) { unsigned long a=0 , b=1 , i, tmp; for (i=0 ; i<n; ++i) { tmp = a; a = a + b; b = tmp; } return a; }
cfib.h
內容如下:
1 2 3 4 5 6 #ifndef __CFIB_H__ #define __CFIB_H__ unsigned long fib (unsigned long n) ;#endif
基本上cfib.c
跟cfib.h
就是很標準的c程式寫法,就不贅述,主要是拿來比performance用的
下面則是fix.pyx
檔案,fib_c
是定義引用的c函數
fib_cython
是未優化過的cython程式,基本上就是python樣子
fib_cython_optimized
是加上型別的cythoin程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 cdef extern from "cfib.h": unsigned long _fib "fib"(unsigned long n) def fib_c(n): ''' Returns the nth Fibonacci number.''' return _fib(n) def fib_cython(n): '''Returns the nth Fibonacci number.''' a, b = 0, 1 for i in range(n): a, b = a + b, a return a def fib_cython_optimized(unsigned long n): '''Returns the nth Fibonacci number.''' cdef unsigned long a=0, b=1, i for i in range(n): a, b = a + b, a return a
__init__.py
檔案內容:
setup.py
檔案內容如下:
1 2 3 4 from distutils.core import setup, Extensionfrom Cython.Build import cythonizesetup(ext_modules = cythonize(Extension(name="fib" , sources=["cfib.c" , "fib.pyx" ])))
有了這幾個檔案之後,我們先來設定PyCharm
打開PyCharm,到settings => Tools => External Tools
然後點+,新增一個工具,設定如下:
Porgram
設定$ModuleSdkPath$
,Arguments
設定$FilePath$ build_ext --inplace
,Working directory
設定$FileDir$
這樣基本上就大功告成了,然後回到Project對setup.py點右鍵,選External Tools
,選CythonBuild
就可以看到開始跑了
如果設定對的話,就可以看到編譯成功的訊息
最後就可以來跑跑看啦,main.py
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def fib_python (n ): '''Returns the nth Fibonacci number.''' a, b = 0 , 1 for i in range(n): a, b = a + b, a return a if __name__ == '__main__' : print("##### check result #####" ) import fib print("fib(47) in python:" , fib_python(47 )) print("fib.fib_c(47):" , fib.fib_c(47 )) print("fib.fib_cython(47):" , fib.fib_cython(47 )) print("fib.fib_cython_optimized(47):" , fib.fib_cython_optimized(47 )) print("\n##### performace benchmark #####" ) import timeit python_setup = "from __main__ import fib_python" cython_setup = "import fib" print("Python code: " , timeit.timeit('fib_python(47)' , setup=python_setup), "seconds" ) print("Cython code: " , timeit.timeit('fib.fib_cython(47)' , setup=cython_setup), "seconds" ) print("Optimized Cython code: " , timeit.timeit('fib.fib_cython_optimized(47)' , setup=cython_setup), "seconds" ) print("C code: " , timeit.timeit('fib.fib_c(47)' , setup=cython_setup), "seconds" )
輸出結果就會是下面這樣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 C:\Users\*****\Miniconda3\envs\idp\python.exe D:/Dropbox/Data/programming/Python/Cython/1_fib/main.py ##### check result ##### fib(47) in python: 2971215073 fib.fib_c(47): 2971215073 fib.fib_cython(47): 2971215073 fib.fib_cython_optimized(47): 2971215073 ##### performace benchmark ##### Python code: 2.9352622053858113 seconds Cython code: 1.7331176511158422 seconds Optimized Cython code: 0.14643933094340067 seconds C code: 0.11884286952119272 seconds Process finished with exit code 0