前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python调用golang并回调

python调用golang并回调

作者头像
py3study
发布2020-01-08 18:09:58
1.9K0
发布2020-01-08 18:09:58
举报
文章被收录于专栏:python3python3

最近折腾python交互,也真够呛的,一连玩了好几天,被虐的不要不要的。天天各种百度,Google之间。

好吧,废话少说,转入我们的正题。其实,py调用go一般的函数,只是第一道坎,正主其实是py调用go,并且go还回调py!!!

网上其实这些问题很少,而且有且只有一篇关于go回调py的。

就是如下一位大兄弟写的:https://www.golangtc.com/t/59f858c04ce40d3bf47f5fbc

虽说他是说解决了,问题是下面的解决方案写的真心有问题啊。。。其实,py调用go,他们是通过c来进行桥接(应该是这么说吧),py<——>c<——>go,就是说,py一直认为自己是调用c,go也是如此,并不知其实他们是在互相操作。。。

那么,好办了,py调用go并且回调,在py侧,只要按照py调用c,并且回调就可以了。go侧则go调用c,并且回调c,就可以了。

其实py侧很简单,随便百度一下,应该是正确的。上面那大兄弟写的方法就可以了。问题是go侧,真心坑。。。

当py传入自己的回调,其实是被c包装了一下,然后,go这边接收的其实就是一个c的函数指针!在go里面,c的函数指针,其实就是一个unsafe.Pointer,一个unsafe.Pointer,一个unsafe.Pointer,重要的事情说三次!!!但go获得这东西,它只知道是一个地址啊,不知道是一个什么东西。。。好吧,只能把它重新转回c的函数指针,但这个过程必须要靠一个c函数做过渡!!!!

然而,这样就出现一个坑了!!!那个c函数定义,居然不能跟导出的go函数写在同一个go文件里面!!!否则,会一直报重复定义的错误,呵呵。于是乎,只能这么弄,分三个文件:一个.h文件,两个.go文件。

clib.h

代码语言:javascript
复制
#ifndef CLIB_H
#define CLIB_H
typedef void (*callback)(int);
#endif

这是定义回调结构的。

clibh.go

代码语言:javascript
复制
package main

/*
#include "clib.h"
void TestCCB(int c, callback cb){
    cb(c);
}
*/
import "C"

这是定义go调用c函数的,而且这个必须要有,用来间接调用c回调(py回调)的。

main.go

代码语言:javascript
复制
package main

/*
#include "clib.h"
extern void TestCCB(int c, callback cb);
*/
import "C"
import (
   "unsafe"
)

//export TestCB
func TestCB(a, b int, cb unsafe.Pointer){
   c:=a+b
   
   C.TestCCB(C.int(c), (*[0]byte)(cb))
}

func main() {
}

然后这个,是导出我们的正主:TestCB。其中的参数,cb就是针对c(py)回调的,在函数体里面,其实用TestCCB(中间c函数)来调用这个回调,注意:上方extern void TestCCB(int c, callback cb);只能这么弄了,不能直接在这个.go文件写它的定义。我就是为此折腾了好些天的,直接在里面定义c中间函数,就直接报重复定义了。

然后,编译命令要注意了:

代码语言:javascript
复制
go build -ldflags=-s -buildmode=c-shared -o foo.so clibh.go main.go

两个.go文件,必须要写出来!就是上面那大兄弟说的连个go,当时我看着他说的这个名词,愣了半天,不知他说啥。。。其实就是把该编译的go都写吧。。。不知为啥go编译的时候,不会主动把同一个包的代码都编译在一起。。。随便,能用就行。。。

接下来,在py侧,就很简单了。。。

代码语言:javascript
复制
import ctypes

lib = ctypes.CDLL('./foo.so')

CGOFunc = ctypes.CFUNCTYPE(None, ctypes.c_int32)

def GoCB(c):
    print("c =", c)

cb = CGOFunc(GoCB)
lib.TestCB(5, 6, cb)

这个网上都有说,其实就是py调用c接口,然后c又回调py函数的做法。。。以上。

参考了几个网址:

https://www.golangtc.com/t/59f858c04ce40d3bf47f5fbc

https://github.com/golang/go/wiki/cgo#function-pointer-callbacks

https://xiaowing.github.io/post/howto_call_a_go_func_via_funcpoint_from_cside/

https://studygolang.com/articles/2629

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档