我需要在Go语言中创建一个字符串,长度为1048577个字符(1MB + 1字节)。字符串的内容完全不重要。有没有一种方法可以直接分配它,而不需要连接或使用缓冲区?另外,值得注意的是string的值不会改变。它用于单元测试,以验证过长的字符串是否会返回错误。
mnowg1ta1#
使用strings.builder分配字符串而不使用额外的缓冲区。
var b strings.Builder b.Grow(1048577) for i := 0; i < 1048577; i++ { b.WriteByte(0) } s := b.String()
对Grow方法的调用分配了一个容量为1048577的切片。WriteByte调用将切片填充到容量。String()方法使用unsafe将切片转换为字符串。通过一次写入N个字节的块并在最后填充单个字节,可以减少循环的成本。如果您不反对使用unsafe包,请使用以下命令:
p := make([]byte, 1048577) s := *(*string)(unsafe.Pointer(&p))
如果你想知道如何用最简单的代码来实现这一点,请使用以下代码:
s := string(make([]byte, 1048577)
这种做法不符合问题中提出的要求。它使用额外的缓冲区而不是直接分配字符串。
zmeyuzjn2#
我最终使用了这个:
string(make([]byte, 1048577))
https://play.golang.org/p/afPukPc1Esr
pcww981p3#
为了创建大字符串,我做了3个步骤:
BStrAlloc指定最大大小。重要的是要估计大小,最好输入更多。BStrAdd函数用于添加字符串。最后,BStrEnd返回结果字符串。BStrTest显示仅添加字符串通常需要近55秒的应用程序。使用BStr只需要38毫秒。
//------------- fast string add (for big strings)----------------------- func BStrAlloc(pStr string, pMaxLen int) ([]byte, int) { //Alloc| Add,Add...| End var b []byte if len(pStr) > pMaxLen || pMaxLen < 1 { return b, -1 } b = make([]byte, pMaxLen, pMaxLen) reader := strings.NewReader(pStr) for i := 0; i < len(pStr); i++ { char, _ := reader.ReadByte() b[i] = char } reader = nil return b, len(pStr) } func BStrAdd(b []byte, pLen int, pAddStr string) ([]byte, int) { //Alloc| Add,Add...| End if len(pAddStr)+pLen > cap(b) { return b, pLen } reader := strings.NewReader(pAddStr) for i := pLen; i < pLen+len(pAddStr); i++ { char, _ := reader.ReadByte() b[i] = char } reader = nil //save memory return b, pLen + len(pAddStr) } func BStrEnd(b []byte, pLen int) string { //Alloc| Add,Add...| End t := string(b[0:pLen]) b = nil //save memory return t } func BStrTest() { s := "" cnt := 500000 start1 := StartDuration() for i := 0; i < cnt; i++ { s += "ABCD" } fmt.Println("String add:" + StopDuration(start1) + " len:" + fmt.Sprint(len(s)) + " " + Sub(s, 0, 100)) //duration: 00:54.084 s = "" start2 := StartDuration() b, bLen := BStrAlloc(s, 4*cnt+1000) //Alloc| Add,Add...| End if bLen > -1 { for i := 0; i < cnt; i++ { b, bLen = BStrAdd(b, bLen, "ABCD") } } s = BStrEnd(b, bLen) fmt.Println("BStrAdd:" + StopDuration(start2) + " len:" + fmt.Sprint(len(s)) + " " + Sub(s, 0, 100)) // duration: 00:00.038 }
3条答案
按热度按时间mnowg1ta1#
使用strings.builder分配字符串而不使用额外的缓冲区。
对Grow方法的调用分配了一个容量为1048577的切片。WriteByte调用将切片填充到容量。String()方法使用unsafe将切片转换为字符串。
通过一次写入N个字节的块并在最后填充单个字节,可以减少循环的成本。
如果您不反对使用unsafe包,请使用以下命令:
如果你想知道如何用最简单的代码来实现这一点,请使用以下代码:
这种做法不符合问题中提出的要求。它使用额外的缓冲区而不是直接分配字符串。
zmeyuzjn2#
我最终使用了这个:
https://play.golang.org/p/afPukPc1Esr
pcww981p3#
为了创建大字符串,我做了3个步骤:
BStrAlloc指定最大大小。重要的是要估计大小,最好输入更多。BStrAdd函数用于添加字符串。最后,BStrEnd返回结果字符串。BStrTest显示仅添加字符串通常需要近55秒的应用程序。使用BStr只需要38毫秒。