概述
如何在Go中调用Python3的代码不再赘述,网上一大把。但是在协程中多次调用Python函数会panic。
python demo:
# coding: utf-8
def test(a, b):
return a + b
Goalng demo
package main
import (
"fmt"
"sync"
"github.com/DataDog/go-python3"
)
func init() {
python3.Py_Initialize()
}
var PyStr = python3.PyUnicode_FromString
var GoStr = python3.PyUnicode_AsUTF8
func main() {
InsertBeforeSysPath("/usr/local/lib/python3.7/site-packages/")
hello := ImportModule("/Users/xiangxianzhang/go/src/awesomeProject", "test")
hi := hello.GetAttrString("test")
bArgs := python3.PyTuple_New(2)
python3.PyTuple_SetItem(bArgs, 0, PyStr("xixi"))
python3.PyTuple_SetItem(bArgs, 1, PyStr("xixi"))
var wg sync.WaitGroup
for i :=0; i < 5; i ++ {
wg.Add(1)
go func() {
defer wg.Done()
res := hi.Call(bArgs, python3.Py_None)
fmt.Printf("[CALL] hi('xixi') = %sn", GoStr(res))
}()
}
wg.Wait()
select {
}
}
// InsertBeforeSysPath will add given dir to python import path
func InsertBeforeSysPath(p string) string {
sysModule := python3.PyImport_ImportModule("sys")
path := sysModule.GetAttrString("path")
python3.PyList_Insert(path, 0, PyStr(p))
return GoStr(path.Repr())
}
// ImportModule will import python module from given directory
func ImportModule(dir, name string) *python3.PyObject {
sysModule := python3.PyImport_ImportModule("sys")
path := sysModule.GetAttrString("path")
python3.PyList_Insert(path, 0, python3.PyUnicode_FromString(dir))
return python3.PyImport_ImportModule(name)
}
执行:
✘ ⚙ ~/go/src/awesomeProject go run main.go
[FUNC] hi = &python3.PyObject{ob_refcnt:2, ob_type:(*python3._Ctype_struct__typeobject)(0x4390fa0)}
fatal error: unexpected signal during runtime execution
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x421f7e6]
runtime stack:
runtime.throw(0x40e1cd5, 0x2a)
/usr/local/go/src/runtime/panic.go:1116 +0x72
runtime.sigpanic()
/usr/local/go/src/runtime/signal_unix.go:704 +0x48c
goroutine 20 [syscall]:
runtime.cgocall(0x40b0170, 0xc000038ee0, 0x0)
/usr/local/go/src/runtime/cgocall.go:133 +0x5b fp=0xc000038eb0 sp=0xc000038e78 pc=0x40048db
github.com/DataDog/go-python3._Cfunc_PyObject_Call(0xbc14a70, 0xd1772d0, 0x4398138, 0x0)
_cgo_gotypes.go:4351 +0x4e fp=0xc000038ee0 sp=0xc000038eb0 pc=0x40aaaae
github.com/DataDog/go-python3.(*PyObject).Call.func1(0xbc14a70, 0xd1772d0, 0x4398138, 0x0)
/Users/xiangxianzhang/go/pkg/mod/github.com/!data!dog/go-python3@v0.0.0-20211102160307-40adc605f1fe/object.go:160 +0xab fp=0xc000038f10 sp=0xc000038ee0 pc=0x40abacb
github.com/DataDog/go-python3.(*PyObject).Call(0xbc14a70, 0xd1772d0, 0x4398138, 0x0)
/Users/xiangxianzhang/go/pkg/mod/github.com/!data!dog/go-python3@v0.0.0-20211102160307-40adc605f1fe/object.go:160 +0x3f fp=0xc000038f40 sp=0xc000038f10 pc=0x40ab49f
main.main.func1(0xc0000aa030, 0xbc14a70, 0xd1772d0)
/Users/xiangxianzhang/go/src/awesomeProject/main.go:33 +0x76 fp=0xc000038fc8 sp=0xc000038f40 pc=0x40ad736
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1374 +0x1 fp=0xc000038fd0 sp=0xc000038fc8 pc=0x4064921
created by main.main
/Users/xiangxianzhang/go/src/awesomeProject/main.go:31 +0x205
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc0000aa038)
/usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc0000aa030)
/usr/local/go/src/sync/waitgroup.go:130 +0x65
main.main()
/Users/xiangxianzhang/go/src/awesomeProject/main.go:37 +0x225
关于这个问题我在github上提过issue。这是由于直接使用go来调用python函数,不会产生GIL锁,这可能会导致竞争条件,从而导致致命的运行时错误,并且很可能出现分段错误导致整个 Go 应用程序崩溃。
解决方案:
func main() {
InsertBeforeSysPath("/usr/local/lib/python3.7/site-packages/")
hello := ImportModule("/Users/xiangxianzhang/go/src/awesomeProject", "test")
hi := hello.GetAttrString("test")
bArgs := python3.PyTuple_New(2)
python3.PyTuple_SetItem(bArgs, 0, PyStr("xixi"))
python3.PyTuple_SetItem(bArgs, 1, PyStr("xixi"))
state := python3.PyEval_SaveThread()
var wg sync.WaitGroup
for i :=0; i < 5; i ++ {
wg.Add(1)
go func() {
defer wg.Done()
_gstate := python3.PyGILState_Ensure()
defer python3.PyGILState_Release(_gstate)
res := hi.Call(bArgs, python3.Py_None)
fmt.Printf("[CALL] hi('xixi') = %sn", GoStr(res))
}()
}
wg.Wait()
python3.PyEval_RestoreThread(state)
python3.Py_Finalize()
select {
}
}
最后
以上就是舒服唇膏为你收集整理的Golang协程中调用Python3的全部内容,希望文章能够帮你解决Golang协程中调用Python3所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复