雖然Python優點很多,但是有一個致命的缺點就是運行速度太慢,那么Python程序需要一些計算量比較大的模塊時一般會調用c或者c++的代碼來重寫,但是c/c++編寫代碼代價太高,耗費太多的人力,開發周期太長,那么就想到來一個折中的方法是用golang語言。
雖然golang性能比不上c、c++,但是golang天生的高並發,以及編譯速度超級快,而且還自帶垃圾回收機制,不用開發者自己去管理內存,開發效率高。所以在Python程序遇到大計算量時,可以考慮調用go模塊。接下來我們來看看如何在利用go模塊寫Python第三方模塊,以及如何在Python中導入並調用。
下面構建一個go python 模塊:
package main import "C" //指定那些函數能被外部調用 //export test func test() int{ //計算 0-100000 的和 var s int for a := 0; a <= 1000000; a++ { s += a } return s } func main(){ }
編譯生成動態鏈接庫,生成的.so文件可以被python加載並調用
但是有一個需要注意的地方:
Python是利用ctypes
來跟so模塊進行交互,其中存在着一個代碼的翻譯過程,包括數據類型的翻譯,如果需要傳參獲取接收返回值,需要在golang中將參數按照下表對應,定義成C語言的數據類型。
python,ctypes , c 對應類型參考 python 官方文檔:https://docs.python.org/3.5/library/ctypes.html
這里列舉幾個常用的數據類型
ctypes type(ctypes類型) | C type(c語言類型) | Python type(python類型) |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1-character bytes object |
c_wchar | wchar_t | 1-character string |
c_byte | char | int |
c_char_p | char * (NUL terminated) | 1-character bytes object |
c_wchar_p | wchar_t * (NUL terminated) | string or None |
比如創建一個帶參數的go函數:
// 指定接收的參數為c類型的字符串,返回c類型字符串 //pxport addstr func addstr(a,b * C.char) *C.char{ merge := C.GoString(a) + C.GoString(b) return C.CString(merge) }
寫好go代碼之后重新生成動態鏈接庫
go build -buildmode=c-shared -o hello.so src/hello.go
在python中調用帶參數的go模塊需要顯式指定參數的類型以及返回的數據類型。argtypes指定參數類型,restype
指定返回值類型。
from ctypes import CDLL add = CDLL('./hello.so').addstr #調用go模塊 # 顯式聲明參數和返回的期望類型 add.argtypes = [ctypes.c_char_p, ctypes.c_char_p] add.restype = ctypes.c_char_p print(add('haha','hehe')) # 無參數,則可直接調用 t = CDLL('./hello.so').test #調用go模塊 print(t())
python 中調用go模塊,並統計兩個模塊循環1百萬次累加的時間,查看go跟python執行效率
# coding=utf-8 import time from ctypes import CDLL import ctypes def xu(): # python 計算累加 sum = 0 for i in range(0,1000000+1): sum += i return sum if __name__ =="__main__": add = CDLL('./hello.so').addstr #調用go模塊addstr方法 # 顯式聲明參數和返回的期望類型 add.argtypes = [ctypes.c_char_p, ctypes.c_char_p] add.restype = ctypes.c_char_p print(add('haha','hehe')) # go 一百萬次累加 start = time.time() t = CDLL('./hello.so').test #調用go模塊test方法 t.restype = ctypes.c_int64 # 返回int64類型 print("go執行結果:%s"%t()) end = time.time() print("go :1000000 累加耗時 %.2f" %(end-start)) # python累加一百萬次 start = time.time() print("python執行結果:%s"%xu()) end = time.time() print("python :1000000 累加耗時 %.2f" %(end-start))
單從循環一百萬次來看,go的效率要高很多。
Python 號稱開發速度快,而go語言在靜態語言中也號稱是開發開發速度最快的,go的高並發剛好可以填補Python GIL導致Python多線程不是真的多線程這一缺點。
本文主要講解了如何使用golang寫Python模塊,以及在Python中如何調用go模塊,主要要注意的是參數類型的轉換。