Python 访问golang中的C数组
我有两个文件,Python 访问golang中的C数组,python,go,ctypes,Python,Go,Ctypes,我有两个文件,module.go和test.py。我的目标是加速一些用python完成的计算,但在访问go中的整数数组时会遇到问题 module.go package main import "C" //export Example func Example(testArray []C.int) C.int { return testArray[2] } func main() {} 以及python中的简单测试文件: from ctypes import * # Load c
module.go
和test.py
。我的目标是加速一些用python完成的计算,但在访问go中的整数数组时会遇到问题
module.go
package main
import "C"
//export Example
func Example(testArray []C.int) C.int {
return testArray[2]
}
func main() {}
以及python中的简单测试文件:
from ctypes import *
# Load compiled go module
lib = cdll.LoadLibrary("./gomodule.so")
# We are passing an array of 256 elements and recieving integer
lib.Example.argtypes = [c_int * 256]
lib.Example.restype = c_int
pyarr = [x for x in range(256)]
# Make C array from py array
arr = (c_int * len(pyarr))(*pyarr)
print lib.Example(arr)
使用go build-buildmode=c-shared-o gomodule.so module.go编译go模块后,启动python文件,我得到:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x12 pc=0x7fb18b6e688c]
goroutine 17 [running, locked to thread]:
main.Example(...)
/home/metro/go/src/github.com/golubaca/carinago/module.go:7
main._cgoexpwrap_53c1c00d0ad3_Example(0xa, 0x7fff33a2eac0, 0x7fff33a2ea70, 0x722a921de6cae100)
_cgo_gotypes.go:47 +0x1c
Aborted (core dumped)
我知道C数组与Go不同,但是找不到任何教程如何在不惊慌的情况下访问它的值。C中的数组不能自动转换为Go中的切片。请注意,在Go中,切片有两部分:长度和指向备份数据的指针
因此,您必须从指针手动创建切片
package main
import (
"C"
"reflect"
"unsafe"
)
//export Example
func Example(carr *C.int, size int, idx int) C.int {
// Build the slice manually using unsafe
var slice []C.int
header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
header.Cap = size
header.Len = size
header.Data = uintptr(unsafe.Pointer(carr))
return slice[idx]
}
func main() {}
然后在python代码中调用Go exported函数,如下所示:
from ctypes import *
# Load compiled go module
lib = cdll.LoadLibrary("./gomodule.so")
# We are passing an array of 256 elements and recieving integer
lib.Example.argtypes = [c_int * 256]
lib.Example.restype = c_int
pyarr = [x for x in range(256)]
# Make C array from py array
arr = (c_int * len(pyarr))(*pyarr)
print lib.Example(arr, len(arr), 4)
上面的示例应该打印数组的第四个索引元素这是惯用的、高效的Go解决方案(避免反射)
module.go
:
package main
import "C"
import "unsafe"
//export Example
func Example(cArray *C.int, cSize C.int, i C.int) C.int {
gSlice := (*[1 << 30]C.int)(unsafe.Pointer(cArray))[:cSize:cSize]
return gSlice[i]
}
func main() {}
输出:
$ go build -buildmode=c-shared -o gomodule.so module.go
$ python test.py
4
$
作为建议,你看过numpy吗?(我公开承认我不知道这段代码中发生了什么。但是,“整数数组”的计算听起来像是numpy部门。它在加速计算方面帮了我很多)是的,我有,但我想使用go,因为我已经有了一些其他代码,我想将许可证签入作为文件进行集成,所以文件,因为它至少比普通python文件或pyc更难逆转engeneer。所以这里的主要思想是在go中对关键代码部分使用许可证检查,并一起编译。这是正确的答案。我没有想到头,但现在我知道了寻找其他类型的头。谢谢!很好,我尝试了这个,结果与第一个答案相同,但共享对象的文件大小更小,这很好。我必须接受这个“被接受”的答案,因为转换效率很高。非常感谢你们两位。[1@Nathan.:Go数组必须有一个声明的大小。这设置了片的最大允许大小和容量。Go将根据参数构造实际的片头,并使用数组的基作为基础数组。因此,如果数组中实际有256C.int
s,则片将以此作为其长度和容量Go无法访问实际阵列之外的区域。
$ go build -buildmode=c-shared -o gomodule.so module.go
$ python test.py
4
$