當然了,現在我們大部分程式都是(IO)網路密集型程序,Python足以勝任,但是如果說我們已經存在的專案或想要開發的專案中,存在著有運算密集的程式場景,我們該怎麼辦呢?
可能有的夥伴聽過Python C\C ,用C\C 重寫Python計算密集的地方,來提升效能。
當然, 這是一個很好的解決方法,但我們知道C\C 是有一些學習成本,有沒有再更好的解決方案呢?
#/2 嘗試在Python中呼叫Golang程式碼/
後來有幸接觸到了Golang,使用了一端時間小編就在想,Python要是能調用Go代碼就好了,實在是不想學習C\C ,畢竟C\C的指針和自己釋放內存還是比較有門檻的,Go就很方便了,垃圾自動回收,省的內存洩漏還有天生高並發等優勢。
經過不斷的查閱了一些資料,踩了一些坑,功夫不負有心人,終於找到了合適的辦法,在此分享給大家。
目前最廣泛的Python解釋器是CPython,Python正好留出來有可以呼叫C\C 程式碼的模組,Go經過一些方法,也是可以編譯成類似Python可呼叫的C\C 的文件。
#/3 測試環境/
系統:windows
Python解釋器:Python 3.7.6(64位元)
Go編譯器:#Go 1.14(64位元)
#/4 效能比較/
為了更好的體現出來優化之後的效果,我們大概會比較一下兩個語言在計算密集情況下的差距。
檢定:分別計算一個億(100000000)的累積模擬大量計算。
1)Python程式碼
import time def run(n): sum = 0 for i in range(n): sum += i print(sum) if __name__ == '__main__': startTime = time.time() run(100000000) endTime = time.time() print("耗时:", endTime - startTime)
可以看到耗時:10s左右,如下圖所示。
2)Go程式碼
package main import ( "fmt" "time" ) func run(n int) { sum := 0 for i := 0; i < n; i++ { sum += i } fmt.Println(sum) } func main() { var startTime = time.Now() run(100000000) fmt.Println("耗时:", time.Since(startTime)) }
可以看到耗時:200ms左右,如下圖所示。
3)测试结论
我们可以看到,在计算方面,Python和Go是有很大的差距的,如果计算这一块能放在Go上就好了。
别着急,马上开始。
/5 Go代码编译为Python可调用的.so文件/
1)Go代码
功能:接收传入的值进行累加,并且返回最终的累加值。
package main import ( "C" //C必须导入 ) //export run func run(n int) int{ /* 必须要export 函数名 //是注释的意思,相当于Python中的 # 我也是第一次见注释还有作用,黑人三问好??? 固定写法 */ sum := 0 for i := 0; i < n; i++ { sum += i } fmt.Println("我是Go代码,我跑完了,我的结果是:",sum) return sum } func main() { //main函数中什么都不要写,和包名main要对应 }
命令如下:
go build -buildmode=c-shared -o 输出的.so文件 go源文件
例如:
go build -buildmode=c-shared -o s1.so s1.go
会生成.h文件和.so文件,.so文件供Python调用,如下图所示:
依然是计算一个亿,关键部分由Go生成的.so执行。
from ctypes import * import time if __name__ == '__main__': startTime = time.time() s = CDLL("s1.so") # 加载s1.so文件 result = s.run(100000000) # 调用Go生成的.so文件里面的run函数 print("result:", result) endTime = time.time() print("耗时:", endTime - startTime)
我们可以看到,虽然速度很快,但是Python在调用Go生成的.so文件之后,拿到的返回值竟然是错的,但是在Go中打印的确实对的,这是为什么呢???
不要慌,问题不大!我们来计算一次稍微小一点的,上个100w的。
额,怎么还是错误。
6)我们再来计算更小一些的数,以10023为例,一个不零不整的数值。
這次可以看到,結果是對的。但是100w 結果為什麼會是錯的呢? ? ?
我們上述可以知道,.so文件計算的結果卻是正確的,可能是在python接收的時候轉換的時候錯了,不過別捉急,本章已經有點長了,在下章一定會把這個坑解決的,敬請期待~
#/6 小結/
以上是【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能的詳細內容。更多資訊請關注PHP中文網其他相關文章!