在Go中分配大字符串的最快方法是什么?

vsmadaxz  于 2023-09-28  发布在  Go
关注(0)|答案(3)|浏览(93)

我需要在Go语言中创建一个字符串,长度为1048577个字符(1MB + 1字节)。字符串的内容完全不重要。有没有一种方法可以直接分配它,而不需要连接或使用缓冲区?
另外,值得注意的是string的值不会改变。它用于单元测试,以验证过长的字符串是否会返回错误。

mnowg1ta

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)

这种做法不符合问题中提出的要求。它使用额外的缓冲区而不是直接分配字符串。

zmeyuzjn

zmeyuzjn2#

我最终使用了这个:

string(make([]byte, 1048577))

https://play.golang.org/p/afPukPc1Esr

pcww981p

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
}

相关问题