一、调用步骤:

  将go代码编译成so库 -> python中通过ctypes引用so库并指定需要调用的函数(同时可指定传入参数类型和返回值类型) -> 指定后按python使用函数方式调用。

  需要注意的是:python和go之间参数传递是需要经过C的数据类型转换的,因此需要了解python中ctypes数据类型和python数据类型以及C的数据类型对应关系

  三种数据类型使用场景:1. ctypes数据类型为指定调用函数时的传入参数和返回值的数据类型

             2. python数据类型为调用函数时传入的参数的数据类型

               3. C的数据类型为go代码中定义的函数所需的参数和返回值数据类型

  类型对应如下:文档传送地址

  由此举例:当python传入的参数需是string时,ctypes中指定的传参参数类型需为c_wchar_p,go中需要指定接收的参数数据类型为 *C.wchar_t。

  由于不知道go中如何将字符串和*C.wchar_t互相转化,因此我这里将python传入的参数指定为bytes,即ctypes中指定的传参参数类型需为c_char_p,go中需要指定接收的参数数据类型为*C.char。

二、下面开始实践:

1. 编写go代码

写一个rocketmq的producer函数(main.go),封装成Send函数如下:

 1 package main
2
3 import (
4 "C"
5 "context"
6 "github.com/apache/rocketmq-client-go/v2"
7 "github.com/apache/rocketmq-client-go/v2/primitive"
8 "github.com/apache/rocketmq-client-go/v2/producer"
9 "os"
10 )
11
12 var (
13 nameservs = []string{"192.168.2.1:9876"}
14 group = "demo.xy"
15 topic = "test"
16 )
17
18 //export Send
19 func Send(cid, message *C.char) *C.char {
20 p, err := rocketmq.NewProducer(
21 producer.WithNsResolver(primitive.NewPassthroughResolver(nameservs)),
22 producer.WithRetry(2),
23 producer.WithGroupName(group),
24 )
25 if err != nil {
26 return C.CString("create producer failed")
27 os.Exit(-1)
28 }
29
30 err = p.Start()
31 if err != nil {
32 return C.CString("start producer failed")
33 os.Exit(-1)
34 } else {
35 defer p.Shutdown()
36 }
37
38 msg := &primitive.Message{
39 Topic: topic,
40 Body: []byte(C.GoString(message)),
41 }
42 msg.WithTag(C.GoString(cid))
43
44 _, err = p.SendSync(context.Background(), msg)
45 if err != nil {
46 return C.CString("producer send message failed")
47 } else {
48 return C.CString("producer send message success")
49 }
50 }
51
52 func main() {}

需要注意:1). Go里面将C的char指针类型数据通过C.GoString()转化成go中的字符串;反之通过C.CString()将go中的字符串转化为C的char指针类型数据。具体类型转化方式可查阅相关文档(待补充)

       2). python需要调用的函数必须在函数上方用 //export [函数名称] 加上说明,不然python中会报AttrbuteError错误(symbol not found)

2. 将go代码编译成so动态链接库

go build --buildmode=c-shared -o producer.so main.go

编译好后会生成两个文件:producer.so和producer.h

3. python中导入so文件并调用对应的函数

 1 import ctypes
2 import json
3
4 # 指定go中的Send函数
5 SendSync = ctypes.CDLL("./producer.so").Send
6 # 指定调用函数时传入的参数数据类型
7 SendSync.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
8 # 指定调用函数返回值的数据类型
9 SendSync.restype = ctypes.c_char_p
10
11 cid = "123454321"
12 message = {
13 "cid": "123454321",
14 "cname": "指南朝北枪",
15 "age": 18,
16 "height": 1.88
17 }
18
19 result = SendSync(cid.encode("utf-8"), json.dumps(message).encode("utf-8"))
20 print(result, type(result))

需要注意的是:1). python2中的字节串是str;字符串是unicode。因此如果是python2调用SendSync函数时不需要使用encode,直接传入str即可

       2). python3中字节串是bytes;字符串是str。因此调用SendSync函数时需要将字符串str通过encode转换成bytes

         3). 指定的参数类型和传入参数类型一定要一致,否者报ctypes.ArgumentError错误(wrong type)

python调用golang代码的更多相关文章

  1. Python调用golang

    有些时候因为效率问题部分代码会 使用Python调用go的编译生成动态链接库go 代码示例//add.gopackage main import "C" //export Addf ...

  2. Python调用Java代码部署及初步使用

    Python调用Java代码部署: jpype下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#jpype 下载的时候需要使用Chrome浏览器进行下载 ...

  3. 如何实现Python调用C代码--python与C之间如何通信(swig)

    转载: https://www.zhihu.com/question/23003213 1. C代码如何调用Python 1.1 test #include <Python.h> int ...

  4. python 调用 java代码

    一.JPype简述 1.JPype是什么? JPype是一个能够让 python 代码方便地调用 Java 代码的工具,从而克服了 python 在某些领域(如服务器端编程)中的不足. 2.JPype ...

  5. python调用Go代码

    Go 1.5发布了,其中包含了一个特性:可以编译生成动态链接库,经试验,生成的.so文件可以被python加载并调用.下面举个例子: 先写一个go文件main.go: package main imp ...

  6. 转python调用Go代码

    Go 1.5发布了,其中包含了一个特性:可以编译生成动态链接库,经试验,生成的.so文件可以被python加载并调用.下面举个例子: 先写一个go文件main.go: package main imp ...

  7. python调用Java代码,完毕JBPM工作流application

    1.缘由 有一庞大Python django webproject,要引入工作流引擎,像OA一样.方便的流程控制与管理.Python或django关于工作流的开源插件,稀少,并且弱爆了,终于选用jav ...

  8. python调用c代码2

    1.生成动态链接库 [root@typhoeus79 c]# more head.c #include <stdio.h> #include <stdlib.h> typede ...

  9. python调用c代码

    Linux环境下使用python调用C的printf例子: #!/usr/bin/env python2.7 #-*- coding:utf-8 -*- from ctypes import * de ...

  10. python调用java代码 java虚拟机(jvm)

    1.新建com文件夹,在里面新建 fibnq.java package com; public class fibnq { public fibnq(){} public int fb(int n){ ...

随机推荐

  1. 初始rust

    安装rust 访问rust 按照步骤操作即可,安装很慢,请耐心等待 安装成功之后,请注意在命令行测试 rustc --version,cargo --version看看输出版本信息是否正常,如果不正常 ...

  2. 字符输入流读取字符数据-writer类

    字符输入流读取字符数据 读取字符:read方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1,循环读取,代码使用演示∶ writer类 java.io.Filelwriter ...

  3. Ubuntu 22.04 GCC Arm 12.2.rel1编译 DAPLink

    ARMmbed / DAPLink 项目 仓库地址 https://github.com/ARMmbed/DAPLink Arm Mbed 应该属于Arm的机构或者是Arm资助的机构. 常用的 DAP ...

  4. 【总结笔记】全志平台 Linux ASOC 框架浅析

    ASOC 各部分框图示意 Platform 一般由 SOC 芯片原厂负责编写,主要涉及到 SOC 内部数字音频接口DAI(I2S)和 DMA 的寄存器配置. Codec 一般由硬件方案的驱动工程师或者 ...

  5. 浅谈Pytest中的marker

    浅谈Pytest中的marker 没有注册marker 我们写一个简单的测试 # test_demo.py import pytest @pytest.mark.login def test_demo ...

  6. 云原生时代顶流消息中间件Apache Pulsar部署实操-上

    @ 目录 安装 运行时Java版本推荐 Locally Standalone集群 启动 验证 部署分布式集群 部署说明 初始化集群元数据 部署BookKeeper 部署Broker Admin客户端和 ...

  7. CNCF社区首个!KubeEdge达到软件供应链SLSA L3等级

    摘要:在v1.13.0版本中,KubeEdge项目已达到 SLSAL3等级(包括二进制和容器镜像构件),成为CNCF社区首个达到SLSA L3等级的项目. 本文分享自华为云社区<CNCF社区首个 ...

  8. 原生微信小程序的一些注意点

    1.微信小程序的数据更新 Page({ // 响应式的数据定义在data里面 data: { bannerList: [] }, // 微信小程序的数据更新是在setData里面做的 this.set ...

  9. 大规模 IoT 边缘容器集群管理的几种架构-1-Rancher+K3s

    前文回顾 大规模 IoT 边缘容器集群管理的几种架构-0-边缘容器及架构简介 ️Reference: IoT 边缘计算系列文章 Rancher + K3s 简介 Rancher: Kubernetes ...

  10. 代码随想录算法训练营day14 | leetcode 层序遍历 226.翻转二叉树 101.对称二叉树 2

    层序遍历 /** * 二叉树的层序遍历 */ class QueueTraverse { /** * 存放一层一层的数据 */ public List<List<Integer>&g ...