• python调用golang代码


    一、调用步骤:

      将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)

  • 相关阅读:
    Alpha冲刺(8/10)
    Alpha冲刺(7/10)
    Alpha冲刺6
    Alpha冲刺5
    GIT团队实战博客
    Alpha冲刺4
    STM32和WM8960 I2S 利用DMA双缓冲音频播放和录音(二)
    STM32和WM8960 I2S 利用DMA双缓冲音频播放和录音(一)
    USART DMA双缓冲给PC发送数据和接收PC数据
    详细理解STM32F42x系列的DMA配置
  • 原文地址:https://www.cnblogs.com/zzmx0/p/16027864.html
Copyright © 2020-2023  润新知