Dalam artikel sebelum ini, kami berjaya memanggil kod Go melalui Python dan menyerahkan pengiraan intensif kepada Go Walaupun pengiraan sangat pantas, apabila mendapat nilai pulangan, nampaknya agak mengejutkan, tidak seperti yang kami bayangkan .
/2 Apakah sebab ralat nilai pulangan? /
Dalam artikel lepas, kita semua seolah-olah terlupa sekeping gambar.
Fail .go kepunyaan Go, .jadi fail yang Python panggil Go. ? ? Ia seolah-olah tidak mempunyai rasa kewujudan Masalah kami terletak pada fail .h ini ditukar kepada C ialah jenis GoInt Apakah maksud jenis ini secara khusus? ? ? Tengok lagi.
Anda mungkin boleh mengetahui daripada perkara di atas bahawa GoInt sebenarnya GoInt64, dan jenis GoInt64 adalah jenis long long Adakah ini sesuatu? ? ?
Malah, apabila kita memanggil fail .so dalam Python, kita menggunakan modul<code style="font-family: var(--monospace);vertical-align: initial;border-width: 1px;border-style: solid;border-color: rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;padding-right: 2px;padding-left: 2px;font-size: 0.9em;"><span style="font-size: 18px;">ctypes</span>
ctypes, ini mempunyai jadual yang sepadan.
/3 Python, ctypes, jadual surat menyurat jenis c/
🎜🎜
ctypes type |
C type |
Python type |
c_bool |
bool (1) |
|
c_char
char |
1 aksara bait objek |
|
c_wchar
wchar_t |
1-rentetan |
1-rentetan | c_byte
char |
int |
| c_ubyte
unsigned char |
int |
c_short |
short |
int |
| pendek tidak bertanda
|
int
|
c_int
|
int
|
int
|
c_uint
|
unsigned int
|
int
| int
|
| long |
int
🎜🎜🎜c_ulong🎜 |
unsigned long |
int |
c_longlong |
__int64 atau long long |
|
c_ulonglong
unsigned __int64 atau unsigned long long |
int |
|
c_size_t
size_t |
int |
|
ize_t atau Py_ssize_t
int |
|
c_float
|
float
apung | .
float
|
c_char_p
|
char * (NUL ditamatkan )
|
bait objek atau Tiada
|
c_wchar_p
|
wchar_t * (NUL ditamatkan)
|
|
|
|
c_void_p
void * |
int atau Tiada |
|
根据上述表格我们可以发现,在C中的long long类型对应的ctype类型是c_longlong。
所以我们需要在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)
Salin selepas log masuk
再次执行:
可以看到,这次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要对应
}
Salin selepas log masuk
下面一起来理解.h文件。编译之后打开.h文件如下图所示:
可以看到,在extern的函数成了两个,但是他的返回值是GoString,继续找。
可以发现,其实GoString就是_GoString_,继续找。
这次是一个结构体,里面其实是两个值,不在是单独的long long了,那Python中的继承类也要改一下了。
下面基本同上。
完整代码如下:
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)
Salin selepas log masuk
结果:
可以看到,调用Go代码成功的拿到了正确的字符串返回值,如果没有 .restype = StrPointer拿到的会是什么呢?拿到会和原来的一样,一堆数字,这里就不举栗子了。
/5 小结/
至此,基本上在Python调用Go代码上的大坑都解决了,最复杂的是返回字符串类型,查了很多相关资料才解决。
关于返回其他类型的Python的class怎么写,我相信已经难为不到你们了,最复杂的都解决了,最简单的还不会吗?(除字符串类型以外其他_fields_都是一个字段的)
我相信各位小伙伴学习能力还是很强的,人生苦短,Python当歌,加油,奥利给!
Atas ialah kandungan terperinci [Lanjutan] Python+Go - Mari cari cara lain untuk meningkatkan prestasi pengkomputeran. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!