是否有一种方法可以直接将golang字符串复制到预分配的C字符缓冲区



我有一个变量(但在组合大小上限)需要传递给C的gostring的数量,我想做到尽可能便宜。我将多次执行此操作(因此可以认为预分配重用的缓冲区是零成本)。

我最初的方法是遍历gostring,将每个gostring转换为CString并将其推入c。

for _, str := range mystrings {
cstr := C.CString(str)
defer C.free(unsafe.Pointer(cstr))
C.push_str(pushStrFn, cstr)
}

当然,由于C.CString,这执行了N次堆分配,以及N次CGo调用-所有这些都不便宜。

下一步是在Go中使用开始时分配的strings.Builder构建一个大字符串,然后在单个CGo调用中将它与一些长度信息一起传递给C。这是一个CString调用和一个CGo调用-一个实质性的改进。

builder.Reset()
for _, str := range mystrings {
builder.WriteString(str)
}
C.push_strs(pushStrsFn, C.CString(builder.String()))

但这种方法仍然是执行一个不必要的副本!理想情况下,我想预先分配一大块内存,我可以传递给C,只是直接复制字符串到它,而不使用一个大的GoString中介。

我能够提前预分配一个大数组,并迭代gostring中的字符,一次复制一个。这避免了中间复制,但比专用的字符串复制函数(如构建器)要慢得多。

cCharArray := C.malloc(C.size_t(MAX_SIZE) * C.size_t(unsafe.Sizeof(uintptr(0))))
goCharArray := (*[1<<30 - 1]C.char)(cCharArray)
for _, str := range mystrings {
for i, c := range str {
goCharArray[offset+i] = C.char(c)
}
}
C.push_charArray(pushCharArrayFn, (*C.char)(cCharArray))

是否有更快的方法来做到这一点,我错过了?我可以以某种方式提供一个C缓冲区到strings.Builder,或使用字符串复制函数直接到C缓冲区?

您是否尝试过C.strncpy,或者这个包装器?https://github.com/chai2010/cgo/blob/master/char.go L61。如果这不是更快,你可以尝试使用unsafe将Go字符串的指针转换为CString指针。

使用不安全的包从C分配的缓冲区中创建字节片。

可以直接复制到该切片中,或者将其作为零长度的切片粘贴到一个字节中。缓冲和使用WriteString。您必须小心不要超过您的原始容量,否则缓冲区会将您的数据复制到新的后备缓冲区。

最新更新