Go:跨團(tuán)隊(duì)協(xié)作時如何共享對象

在一個公司中,跨小組/團(tuán)隊(duì)協(xié)作時如果各方使用不同的語言,有時會很復(fù)雜。在我的團(tuán)隊(duì)[1]中,我們維護(hù)用 Go 語言寫的項(xiàng)目,而我們的合作方,數(shù)據(jù)科學(xué)小組使用 Python。他們提供給我們一些公式,我們需要在項(xiàng)目中翻譯成 Go。
當(dāng)我們實(shí)現(xiàn)了這個公式后,我們需要對方組的驗(yàn)證,以確保我們實(shí)現(xiàn)得沒有錯誤。讓他們來測試并讓他們自己提供測試數(shù)據(jù)無疑是最好的方法。幸運(yùn)的是,我們可以用 Go 來實(shí)現(xiàn)這個過程。
cgo 和共享對象
構(gòu)建命令 go build 有一個參數(shù)可以把你的 Go 包編進(jìn) C shared library[2]:
-buildmode=c-shared
???Build?the?listed?main?package,?plus?all?packages?it?imports,
???into?a?C?shared?library.?The?only?callable?symbols?will
???be?those?functions?exported?using?a?cgo?//export?comment.
???Requires?exactly?one?main?package?to?be?listed.
用這個模式你可以編譯一個 shared library,文件以 “.so” 結(jié)尾,你可以在其他語言中如 C,Java,Ruby 或 Python 中直接使用。然而,這個模式只有 Cgo[3] 支持,你可以在你的 Go 包中寫、調(diào)用 C 代碼。基于此,你可以寫一個自己的庫,讓別的小組用他們自己的語言來調(diào)你的庫。
實(shí)現(xiàn)
Go 和共享對象間的網(wǎng)關(guān)的實(shí)現(xiàn)看起來很簡單。首先你需要在你想導(dǎo)出的每一個函數(shù)前添加注釋 //export MyFunction。然后你需要在強(qiáng)制性 import "C" 之前前置聲明你的 C 結(jié)構(gòu)體。下面是我們代碼的簡化版:
import?(
???/*
???typedef?struct{
???int?from_bedroom;
???int?to_bedroom;
???int?from_price;
???int?to_price;
???int?from_size;
???int?to_size;
???int?types[5];
???}?lead;
???typedef?struct{
???int?bedroom;
???int?price;
???int?size;
???int?type_id;
???}?property;
???*/
???"C"
)
//export?NewProperty
func?NewProperty(b?int,?p?int,?s?int,?t?int)?C.property?{
???//?business?logic
???return?C.property{
??????bedroom:???C.int(b),
??????price:?????C.int(p),
??????size:??????C.int(s),
??????type_id:???C.int(t),
???}
}
//export?NewLead
func?NewLead(fb?int,?tb?int,?fp?int,?tp?int,?fs?int,?ts?int,?t?[]int)?C.lead?{
???//?business?logic
???return?C.lead{
??????from_bedroom:?C.int(fb),
??????to_bedroom:???C.int(tb),
??????from_price:???C.int(fp),
??????to_price:?????C.int(tp),
??????from_size:????C.int(fs),
??????to_size:??????C.int(ts),
??????types:????????types,
???}
}
//export?CalculateDistance
func?CalculateDistance(l?C.lead,?p?C.property)?{
???//?business?logic?here
}
因?yàn)槟悴荒軐?dǎo)出 Go 的結(jié)構(gòu)體,所以你需要把 C 的結(jié)構(gòu)體作為輸入/輸出參數(shù)進(jìn)行處理。當(dāng)你寫完代碼后,可以使用命令 go build -o main.so -buildmode=c-shared main.go 來編譯。為了能編譯成功,你的 Go 代碼中需要有 main 包和 main 函數(shù)。然后,你就可以寫你的 Python 腳本了:
#!/usr/bin/env?python
from?ctypes?import?*
#?loading?shared?object
matching?=?cdll.LoadLibrary("main.so")
#?Go?type
class?GoSlice(Structure):
????_fields_?=?[("data",?POINTER(c_void_p)),?("len",?c_longlong),?("cap",?c_longlong)]
class?Lead(Structure):
????_fields_?=?[('from_bedroom',?c_int),
????????????????('to_bedroom',?c_int),
????????????????('from_price',?c_int),
????????????????('to_price',?c_int),
????????????????('from_size',?c_int),
????????????????('to_size',?c_int),
????????????????('types',?GoSlice)]
class?Property(Structure):
????_fields_?=?[('bedroom',?c_int),
????????????????('price',?c_int),
????????????????('size',?c_int),
????????????????('type_id',?c_int)]
#parameters?definition
matching.NewLead.argtypes?=?[c_int,?c_int,?c_int,?c_int,?c_int,?c_int,?GoSlice]
matching.NewLead.restype?=?Lead
matching.NewProperty.argtypes?=?[c_int,?c_int,?c_int,?c_int]
matching.NewProperty.restype?=?Property
matching.CalculateDistance.argtypes?=?[Lead,?Property]
lead?=?lib.NewLead(
????#?from?bedroom,?to?bedroom
????1,?2,
????#?from?price,?to?price
????80000,?100000,
????#?from?size,?to?size
????750,?1000,
????#?type
????GoSlice((c_void_p?*?5)(1,?2,?3,?4,?5),?5,?5)
)
property?=?lib.NewProperty(2,?90000,?900,?1)
matching.CalculateDistance(lead,?property)
你的共享對象中的所有導(dǎo)出的方法都應(yīng)該在你的 Python 文件中有描述:類型、參數(shù)順序及返回參數(shù)。
之后,你可以運(yùn)行你的 Python 腳本 python3 main.py。
使用的方便程度
乍一看很簡單,但可能需要花費(fèi)很長時間才能正常運(yùn)行。Python 中沒有很多關(guān)于這個的文檔或例子,而且很難調(diào)試。如果用 .argtypes 或 .restype 對你暴露的方法描述不當(dāng),可能會導(dǎo)致意想不到的結(jié)果或出現(xiàn) segmentation fault 錯誤信息,且不會有足夠多的信息來幫助調(diào)試。
這個 Go/Python 的通信方式很適合跨團(tuán)隊(duì)測試,但我不建議在大型的項(xiàng)目或以后在生產(chǎn)環(huán)境中用。因?yàn)檫@種開發(fā)方式很復(fù)雜,容易耗費(fèi)較長時間。
via: https://medium.com/a-journey-with-go/go-shared-objects-for-cross-team-collaboration-b3af7d9e73af
作者:Vincent Blanchon[4]譯者:lxbwolf[5]校對:polaris1119[6]
本文由 GCTT[7] 原創(chuàng)編譯,Go 中文網(wǎng)[8] 榮譽(yù)推出
參考資料
我的團(tuán)隊(duì): https://www.propertyfinder.ae/
[2]把你的 Go 包編進(jìn) C shared library: https://golang.org/pkg/cmd/go/internal/help/#pkg-variables
[3]Cgo: https://golang.org/cmd/cgo/
[4]Vincent Blanchon: https://medium.com/@blanchon.vincent
[5]lxbwolf: https://github.com/lxbwolf
[6]polaris1119: https://github.com/polaris1119
[7]GCTT: https://github.com/studygolang/GCTT
[8]Go 中文網(wǎng): https://studygolang.com/
推薦閱讀

