golang怎么执行python脚本并且带传入参数的 golang执行python代码 您所在的位置:网站首页 golang执行python golang怎么执行python脚本并且带传入参数的 golang执行python代码

golang怎么执行python脚本并且带传入参数的 golang执行python代码

2024-07-02 01:01| 来源: 网络整理| 查看: 265

1. 前言

在上一篇文章中,我们成功的通过 Python 调用 Go 代码,并且把计算密集的交给了 Go 来进行计算

虽然计算的很快,但是在获取返回值时,似乎有点让人诧异,并不是我们想象的那样子

golang怎么执行python脚本并且带传入参数的 golang执行python代码_so文件

2. 返回值错误原因?

在上一篇文章中,我们似乎都忘了一张图

golang怎么执行python脚本并且带传入参数的 golang执行python代码_golang python性能_02

.go 文件是 Go 的,不多说,.so 是 Python 调用 Go 的文件,那 .h 文件是什么?

似乎很没有存在感,我们的问题出,也就出在这个 .h 文件中,我们打开看一下

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Python_03

我们往下翻翻,会找到 extern 开头的声明,这个意思是将 Go 代码转为 C 代码一一对应的参数,可见,转为 C 的是 GoInt 类型,这个类型具体什么意思呢???再找找看

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Go_04

在上面其实大概可以发现,GoInt 其实就是 GoInt64,GoInt64 的类型是 long long 类型,这是玩意???

其实我们在 Python 中调用 .so 文件使用的是 ctypes 模块,这个是有一个对应表的

golang怎么执行python脚本并且带传入参数的 golang执行python代码_so文件_05

3. 查看对应表

对应表可以参考官网地址:

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

在 C 中的 long long 类型对应的 ctype 类型是 c_longlong

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Python_06

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

代码如下:

from ctypes import *

import time

class StructPointer(Structure):

# 根据查表,C中的long long,对应的ctypes 是 c_longlong

# _fields_必须是[](列表)类型,里面写对应的类型,固定格式

_fields_ = [("p", c_longlong,),]

if __name__ == '__main__':

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)

再次执行,结果如下:

golang怎么执行python脚本并且带传入参数的 golang执行python代码_golang python性能_07

可以看到,这次 Python 执行的结果和 Go 执行结果就一个样了。

继续,换个数字试试

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Python_08

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

4. 如果是字符串,怎么办

Go 代码

package main

import (

"C" //C必须导入

"fmt"

)

//export run

func run(n int) int{

/*

必须要export 函数名

//是注释的意思,相当于Python中的 #

我也是第一次见注释还有作用

*/

sum := 0

for i := 0; 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 文件如下图所示:

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Go_09

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

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Go_10

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

golang怎么执行python脚本并且带传入参数的 golang执行python代码_so文件_11

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

golang怎么执行python脚本并且带传入参数的 golang执行python代码_golang python性能_12

下面基本同上

golang怎么执行python脚本并且带传入参数的 golang执行python代码_golang python性能_13

完整代码如下:

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__ == '__main__':

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)

运行后的结果如下:

golang怎么执行python脚本并且带传入参数的 golang执行python代码_Python_14

可以看到,调用 Go 代码成功的拿到了正确的字符串返回值

如果没有 .restype = StrPointer 拿到的会是什么呢?

拿到会和原来的一样,一堆数字,这里就不举例子了



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有