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

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

Go语言进阶学习
Go语言进阶学习轉載
2023-07-20 16:32:25644瀏覽
    在上一篇文章中,我們成功的透過Python呼叫Go程式碼,並且把計算密集的交給了Go來進行計算,雖然計算的很快,但是在取得回傳值時,似乎有點讓人詬異,並不是我們想像的那樣子。

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


#/2 造成回傳值錯誤的原因是什麼? /

        上篇文章中,我們似乎都忘了圖。

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


    .go檔案是Go的,不多說,.so是Python呼叫Go的文件,那.h文件是什麼? ? ?似乎很沒有存在感,我們的問題出,也就出在這個.h檔中,我們打開看一下

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


    我們往下翻翻,會找到extern開頭的聲明,這個意思是將Go代碼轉為C代碼一一對應的參數,可見,轉為C的是GoInt類型,這類型具體什麼意思呢? ? ?再找找看。

#

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

    在上面其實大概可以發現,GoInt其實就是GoInt64,GoInt64的類型是long long類型,這是玩意? ? ?

    其實我們在Python中呼叫.so檔案使用的是<span style="font-size: 18px;">ctypes</span>#模組,這個是有一個對應表的。

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


#/3 Python,ctypes , c 類型對應表/

官網位址:

#
https://docs.python.org/3.5/library/ctypes.html


#c_longdouble##c_longdoublefloat
##ctypes 類型 #C 型別 Python 類型
#c_bool _Bool bool (1)
#c_char char #1 字元位元組物件
c_wchar wchar_t 1 字元字串
c_byte char #int
c_ubyte 無符號字元 int
c_short short int
c_ushort #無符號短整數 int
c_int #int ##int
c_uint #無符號整數 int
c_long int
######### ##### #####c_ulong#### ##unsigned 長 int
c_longlong #__int64 或long long int
c_ulonglong
unsigned __int64 或unsigned long long int
c_size_t #size_t int
#c_ssize_t ######################################## ssize_t 或py_ssize_t############int##################c_float############float## ## ########漂浮###
c_double #double float
####### ######c_char_p############char *(NUL 終止)############bytes 物件或None########## #########c_wchar_p############wchar_t *(NUL 終止)############string 或None######## ##########c_void_p############void *###########int 或None########## ######


    根据上述表格我们可以发现,在C中的long long类型对应的ctype类型是c_longlong。

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


    所以我们需要在Python将.so中的返回值改一下,不能使用系统默认的了。代码如下:

from ctypes import *
import time

class StructPointer(Structure):
    # 根据查表,C中的long long,对应的ctypes 是 c_longlong
    # _fields_必须是[](列表)类型,里面写对应的类型,固定格式
    _fields_ = [("p", c_longlong,),]

if __name__ == &#39;__main__&#39;:
    beginTime = time.time()
    s = CDLL("s1.so")  # 加载s1.so文件
    s.run.restype = StructPointer # 声明.so的run函数返回值类型,固定格式
    result = s.run(100000000)  # 调用Go生成的.so文件里面的run函数

    print("result:", result.p)# 此处需要调用.p来获取值,和 _fields_对应
    endTime = time.time()
    print("耗时:", endTime - beginTime)


    再次执行:

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

    

    可以看到,这次Python执行的结果和Go执行结果就一个样了。继续,换个数字试试看。

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

    基本可以确定,这次是没问题了。


/4 如果返回的是字符串呢?/

Go代码

package main

import (
  "C" //C必须导入
  "fmt"
)

//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
}

//export speak
func speak(n int) string{

  return "OMG 996好累呀,难得休息一天,好好休息"
}
func main() {
  //main函数中什么都不要写,和包名main要对应
}


    下面一起来理解.h文件。编译之后打开.h文件如下图所示:

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


    可以看到,在extern的函数成了两个,但是他的返回值是GoString,继续找。

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


    可以发现,其实GoString就是_GoString_,继续找。

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

    

    这次是一个结构体,里面其实是两个值,不在是单独的long long了,那Python中的继承类也要改一下了。

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


下面基本同上。

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

完整代码如下:

from ctypes import *
import time

class StructPointer(Structure):
    # 根据查表,C中的long long,对应的ctypes 是 c_longlong
    # _fields_必须是[](列表)类型,里面写对应的类型,固定格式
    _fields_ = [("p", c_longlong,),]

class StrPointer(Structure):
    # typedef struct { const char *p; ptrdiff_t n; } _GoString_;
    # ptrdiff_t == long long
    _fields_ = [("p", c_char_p), ("n", c_longlong)]

if __name__ == &#39;__main__&#39;:
    beginTime = time.time()
    s = CDLL("s1.so")  # 加载s1.so文件

    s.run.restype = StructPointer # 声明.so的run函数返回值类型,固定格式
    result = s.run(100000798)  # 调用Go生成的.so文件里面的run函数
    print("result:", result.p)# 此处需要调用.p来获取值,和 _fields_对应

    s.speak.restype = StrPointer
    speakStr = s.speak()
    # 返回的是字节类型,需要转字符串,返回的内容在.p中,.n是切的长度,后面会跟一些介绍,不需要
    speakStr = str(speakStr.p[:speakStr.n], encoding="utf-8")
    print("speak:",speakStr)

    endTime = time.time()
    print("耗时:", endTime - beginTime)


结果:

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

    可以看到,调用Go代码成功的拿到了正确的字符串返回值,如果没有 .restype = StrPointer拿到的会是什么呢?拿到会和原来的一样,一堆数字,这里就不举栗子了。


/5 小结/

    至此,基本上在Python调用Go代码上的大坑都解决了,最复杂的是返回字符串类型,查了很多相关资料才解决。

    关于返回其他类型的Python的class怎么写,我相信已经难为不到你们了,最复杂的都解决了,最简单的还不会吗?(除字符串类型以外其他_fields_都是一个字段的)

    我相信各位小伙伴学习能力还是很强的,人生苦短,Python当歌,加油,奥利给!

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

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