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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM