如何在Go中调用Python3的代码不再赘述,网上一大把。但是在协程中多次调用Python函数会panic。
python demo:
复制代码
1
2
3
4
5# coding: utf-8 def test(a, b): return a + b
Goalng demo
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54package 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) }
执行:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40✘ ⚙ ~/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 应用程序崩溃。
解决方案:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28func 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内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复