有没有办法直接将 golang 字符串复制到预先分配的 C 字符缓冲区
Is there a way to directly copy golang strings to a pre-allocated C char buffer
我有一个可变数量(但以组合大小为上限)的 GoString 需要传递给 C,我想尽可能便宜地完成它。我将多次执行此操作(因此可以将重复使用的预分配缓冲区视为零成本)。
我最初的方法是遍历 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 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 中介。
我能够提前预分配一个大数组,并遍历 GoStrings 中的字符,一次复制一个。这避免了中间复制,但比专用的字符串复制函数(如构建器的函数)要慢得多。
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 指针。
使用 unsafe 包从 C 分配的缓冲区中创建字节片。
然后您可以直接复制到该切片或将其作为零长度重新切片粘贴到 bytes.Buffer 中并使用 WriteString。您必须小心不要超过原始容量,否则缓冲区会将您的数据复制到新的后备缓冲区。
我有一个可变数量(但以组合大小为上限)的 GoString 需要传递给 C,我想尽可能便宜地完成它。我将多次执行此操作(因此可以将重复使用的预分配缓冲区视为零成本)。
我最初的方法是遍历 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 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 中介。
我能够提前预分配一个大数组,并遍历 GoStrings 中的字符,一次复制一个。这避免了中间复制,但比专用的字符串复制函数(如构建器的函数)要慢得多。
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 指针。
使用 unsafe 包从 C 分配的缓冲区中创建字节片。
然后您可以直接复制到该切片或将其作为零长度重新切片粘贴到 bytes.Buffer 中并使用 WriteString。您必须小心不要超过原始容量,否则缓冲区会将您的数据复制到新的后备缓冲区。