Home >Backend Development >Golang >[Advanced] Python+Go - Let's find another way to improve computing performance

[Advanced] Python+Go - Let's find another way to improve computing performance

Go语言进阶学习
Go语言进阶学习forward
2023-07-20 16:32:25723browse
In the previous article, we successfully called the Go code through Python and handed over the intensive calculation to Go for calculation Calculation, although the calculation is very fast, when getting the return value, it seems a bit surprising, not what we imagined.

[Advanced] Python+Go - Let's find another way to improve computing performance


##/2 What is the reason for the return value error? /

In the last article, we seemed to have forgotten a picture.

[Advanced] Python+Go - Let's find another way to improve computing performance


The .go file belongs to Go. Without further ado, .so is the file used by Python to call Go. What is the .h file? ? ? It seems to have no sense of existence. Our problem lies in this .h file. Let’s open it and take a look

[Advanced] Python+Go - Let's find another way to improve computing performance


## We scroll down and we will find the statement starting with extern. This means converting the Go code into C code with one-to-one corresponding parameters. It can be seen that what is converted to C is the GoInt type. What does this type mean? ? ? ? Look again.

[Advanced] Python+Go - Let's find another way to improve computing performance

In fact, you can probably find out from the above that GoInt is actually GoInt64, and the type of GoInt64 is long long type. Is this a thing? ? ?

Actually, when we call the .so file in Python, we use the <span style="font-size: 18px;">ctypes</span> module. This is There is a correspondence table.

[Advanced] Python+Go - Let's find another way to improve computing performance


##/3 Python, ctypes, c type Correspondence table/

Official website address:

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


ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1-character  bytes object
c_wchar wchar_t 1-character  string
c_byte char int
c_ubyte unsigned char int
c_short short int
c_ushort unsigned short int
c_int int int
c_uint unsigned int int
c_long long int
c_ulong unsigned long int
c_longlong __int64 or long long int
c_ulonglong unsigned  __int64 or unsigned long long int
c_size_t size_t int
c_ssize_t ssize_t or Py_ssize_t int
c_float float float
c_double double float
c_longdouble long double float
c_char_p char * (NUL  terminated) bytes object  or None
c_wchar_p wchar_t * (NUL  terminated) string or None
c_void_p void * int or None


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

[Advanced] Python+Go - Let's find another way to improve computing performance


    所以我们需要在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)


    再次执行:

[Advanced] Python+Go - Let's find another way to improve computing performance

    

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

[Advanced] Python+Go - Let's find another way to improve computing performance

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


/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文件如下图所示:

[Advanced] Python+Go - Let's find another way to improve computing performance


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

[Advanced] Python+Go - Let's find another way to improve computing performance


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

[Advanced] Python+Go - Let's find another way to improve computing performance

    

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

[Advanced] Python+Go - Let's find another way to improve computing performance


下面基本同上。

[Advanced] Python+Go - Let's find another way to improve computing performance

完整代码如下:

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)


结果:

[Advanced] Python+Go - Let's find another way to improve computing performance

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


/5 小结/

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

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

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

The above is the detailed content of [Advanced] Python+Go - Let's find another way to improve computing performance. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:Go语言进阶学习. If there is any infringement, please contact admin@php.cn delete