如何在没有内存复制的情况下使用unsafe从字符串中获取字节片 [英] How to use unsafe get a byte slice from a string without memory copy
问题描述
我读到过https://github.com/golang/go/issues/25484关于从[]byte
到string
的无副本转换。
我想知道是否有一种方法可以在没有内存复制的情况下将字符串转换为字节片?
我正在编写一个处理Terra字节数据的程序,如果每个字符串在内存中复制两次,则会减慢进度。而且我不关心可变/不安全,只关心内部使用,我只需要尽可能快的速度。示例:
var s string
// some processing on s, for some reasons, I must use string here
// ...
// then output to a writer
gzipWriter.Write([]byte(s)) // !!! Here I want to avoid the memory copy, no WriteString
因此,问题是:有没有办法防止内存复制?我知道也许我需要不安全的包裹,但我不知道怎么做。我找了一会儿,到现在还没有答案,所以显示的相关答案都不管用。
推荐答案
获取string
的内容而不进行复制通常只能使用unsafe
,因为围棋中的string
是不可变的,如果没有副本,则可以修改string
的内容(通过更改字节切片的元素)。
所以使用unsafe
,它可能是这样的(已更正,工作解决方案):
func unsafeGetBytes(s string) []byte {
return (*[0x7fff0000]byte)(unsafe.Pointer(
(*reflect.StringHeader)(unsafe.Pointer(&s)).Data),
)[:len(s):len(s)]
}
此解决方案来自Ian Lance Taylor。
原始错误解决方案为:
func unsafeGetBytesWRONG(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&s)) // WRONG!!!!
}
有关推理,请参阅下面的Nuno Cruces's answer。
测试:
s := "hi"
data := unsafeGetBytes(s)
fmt.Println(data, string(data))
data = unsafeGetBytes("gopher")
fmt.Println(data, string(data))
输出(在Go Playground上试用):
[104 105] hi
[103 111 112 104 101 114] gopher
但是:您写道,您想要这个,因为您需要性能。您还提到要压缩数据。请注意,压缩数据(使用gzip
)比仅仅复制几个字节需要更多的计算!使用此功能,您不会看到任何显著的性能提升!
string
写入io.Writer
时,建议通过io.WriteString()
函数完成,如果可能,该函数将在不复制string
的情况下完成(通过检查并调用WriteString()
方法,如果该方法存在,则很可能比复制string
更好)。详情请参见What's the difference between ResponseWriter.Write and io.WriteString?还有一些方法可以访问string
的内容,而无需将其转换为[]byte
,例如编制索引,或使用编译器优化副本的循环:
s := "something"
for i, v := range []byte(s) { // Copying s is optimized away
// ...
}
另请参阅相关问题:
golang: []byte(string) vs []byte(*string)
What are the possible consequences of using unsafe conversion from []byte to string in go?
What is the difference between the string and []byte in Go?
Does conversion between alias types in Go create copies?
How does type conversion internally work? What is the memory utilization for the same?
这篇关于如何在没有内存复制的情况下使用unsafe从字符串中获取字节片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!