首頁  >  文章  >  後端開發  >  【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能

Go语言进阶学习
Go语言进阶学习轉載
2023-07-20 16:35:32814瀏覽
    Hello各位小夥伴你們好,我們都知道Python是一個生產力很高的語言,小編本人也非常喜歡Python,經常使用Python幫助小編以最高的效率完成最多的事,但是Python的性能,是我們一直詬病的一個問題,尤其是一個大鎖GIL,有時候想想簡直像吃了蒼蠅一樣有點難受。

    當然了,現在我們大部分程式都是(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左右,如下圖所示。

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能


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左右,如下圖所示。

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能


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要对应
}


2)编译为.so文件供Python调用。

命令如下:

go build -buildmode=c-shared -o 输出的.so文件 go源文件

例如:

go build -buildmode=c-shared -o s1.so s1.go


会生成.h文件和.so文件,.so文件供Python调用,如下图所示:

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能


3)Ptyhon调用so文件

将上述生成的.so文件复制到Python项目的同一级目录。

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能


4)Python代码

依然是计算一个亿,关键部分由Go生成的.so执行。

from ctypes import *
import time


if __name__ == &#39;__main__&#39;:
    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)


可以看到耗时:0.11s左右,如下图所示。

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能


5)为什么计算的耗时时间不一致,难道是计算错了???

    我们可以看到,虽然速度很快,但是Python在调用Go生成的.so文件之后,拿到的返回值竟然是错的,但是在Go中打印的确实对的,这是为什么呢???

    不要慌,问题不大!我们来计算一次稍微小一点的,上个100w的。


【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能


额,怎么还是错误。


6)我们再来计算更小一些的数,以10023为例,一个不零不整的数值。

【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能

    

    這次可以看到,結果是對的。但是100w 結果為什麼會是錯的呢? ? ?

    我們上述可以知道,.so文件計算的結果卻是正確的,可能是在python接收的時候轉換的時候錯了,不過別捉急,本章已經有點長了,在下章一定會把這個坑解決的,敬請期待~

#/6 小結/


##    也許Python Go提高關鍵地方性能和Python C\C 相比不是最好的,但是小編認為該方法卻是最省心的,畢竟C\C 的門檻是比較高的。
    不過話說回來,目前這個表現確實可能也夠用了,畢竟Python Go比Pthon C\C 的效率可能要高上幾倍不止。
#

以上是【基礎篇】Python+Go-帶大家一起另尋途徑提升運算效能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:Go语言进阶学习。如有侵權,請聯絡admin@php.cn刪除