最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang字符串拼接的性能以及原理詳解

 更新時(shí)間:2023年06月09日 11:47:22   作者:Jeson-Sun  
最近在做性能優(yōu)化,有個(gè)函數(shù)里面的耗時(shí)特別長(zhǎng),看里面的操作大多是一些字符串拼接的操作,而字符串拼接在golang里面其實(shí)有很多種實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Golang字符串拼接的性能以及原理的相關(guān)資料,需要的朋友可以參考下

1.字符串高效拼接

在go語(yǔ)言中,字符串(string)是不可變的,因此字符串之間的拼接實(shí)際上是創(chuàng)建了一個(gè)新的字符串。如果頻繁的進(jìn)行字符串拼接,那將會(huì)對(duì)性能產(chǎn)生嚴(yán)重的影響!

1.1常見(jiàn)的拼接方式

(1)使用 +

func plusConcat(n int, str string) string {
	s := ""
	for i := 0; i < n; i++ {
		s += str
	}
	return s
}

(2)使用fmt.Sprintf

func sprintfConcat(n int, str string) string  {
	s := ""
	for i := 0; i < n; i++ {
		s = fmt.Sprintf("%s%s", s, str)
	}
	return s
}

(3) 使用strings.Builder

func builderConcat(n int, str string) string {
	var builder strings.Builder
	for i := 0; i < n; i++ {
		builder.WriteString(str)
	}
	return builder.String()
}

(4) 使用bytes.Buffer

func bufferConcat(n int, str string) string {
	buffer := new(bytes.Buffer)
	for i := 0; i < n; i++ {
		buffer.WriteString(str)
	}
	return buffer.String()
}

(5) 使用[] byte

func byteConcat(n int, str string) string {
	buf := make([]byte, 0, n*len(str))
	for i := 0; i < n; i++ {
		buf = append(buf, str...)
	}
	return string(buf)
}

1.2使用benchmark進(jìn)行性能對(duì)比

測(cè)試代碼:

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randomString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}

func benchmark(b *testing.B, f func(int, string) string) {
	var str = randomString(10)
	for i := 0; i < b.N; i++ {
		f(10000, str)
	}
}

func BenchmarkPlusConcat(b *testing.B)    { benchmark(b, plusConcat) }
func BenchmarkSprintfConcat(b *testing.B) { benchmark(b, sprintfConcat) }
func BenchmarkBuilderConcat(b *testing.B) { benchmark(b, builderConcat) }
func BenchmarkBufferConcat(b *testing.B)  { benchmark(b, bufferConcat) }
func BenchmarkByteConcat(b *testing.B)    { benchmark(b, byteConcat) }

測(cè)試結(jié)果:

$ go test -bench="Concat$" -benchmem .
goos: darwin
goarch: amd64
pkg: example
BenchmarkPlusConcat-8         19      56 ms/op   530 MB/op   10026 allocs/op
BenchmarkSprintfConcat-8      10     112 ms/op   835 MB/op   37435 allocs/op
BenchmarkBuilderConcat-8    8901    0.13 ms/op   0.5 MB/op      23 allocs/op
BenchmarkBufferConcat-8     8130    0.14 ms/op   0.4 MB/op      13 allocs/op
BenchmarkByteConcat-8   17379    0.07 ms/op   0.2 MB/op       2 allocs/op
PASS
ok      example 8.627s

總結(jié): 通過(guò)對(duì)比,發(fā)現(xiàn)fmt.sprintf()+的性能最低,和其他方法相比,性能低了差不多1000倍,且占用內(nèi)存也比其他方法高了1000倍;而其他三者的性能和占用內(nèi)存相差不多;性能最高的方法是[]byte,因?yàn)樘崆胺峙淞俗銐虻膬?nèi)存,所以拼接是不會(huì)進(jìn)行字符串的拷貝與內(nèi)存的重新分配,固效果最佳。

1.3字符串拼接最終建議

綜合易用性和性能,一般推薦使用 strings.Builder 來(lái)拼接字符串。
官方解釋?zhuān)?/strong>

A Builder is used to efficiently build a string using Write methods.
It minimizes memory copying.

如果對(duì) strings.Builder 進(jìn)行內(nèi)存預(yù)分配,性能還可以再次提升??梢允褂肎row()來(lái)對(duì)內(nèi)存進(jìn)行預(yù)分配。
如:

func builderConcat(n int, str string) string {
	var builder strings.Builder
	builer.Grow(n*len(str))
	for i := 0; i < n; i++ {
		builder.WriteString(str)
	}
	return builder.String()
}

2.性能背后的原理

2.1 比較 strings.Builder和 +

strings.Builder 和 + 性能和內(nèi)存消耗差距如此巨大,是因?yàn)閮烧叩膬?nèi)存分配方式不一樣。

  • 字符串在 Go 語(yǔ)言中是不可變類(lèi)型,占用內(nèi)存大小是固定的,當(dāng)使用 +拼接 2 個(gè)字符串時(shí),生成一個(gè)新的字符串,那么就需要開(kāi)辟一段新的空間,新空間的大小是原來(lái)兩個(gè)字符串的大小之和。拼接第三個(gè)字符串時(shí),再開(kāi)辟一段新空間,新空間大小是三個(gè)字符串大小之和,以此類(lèi)推。假設(shè)一個(gè)字符串大小為 10 byte,拼接 1w 次,需要申請(qǐng)的內(nèi)存大小為:

10 + 2 * 10 + 3 * 10 + … + 10000 * 10 byte = 500 MB

  • strings.Builderbytes.Buffer,包括切片 []byte 的內(nèi)存是以倍數(shù)申請(qǐng)的。例如,初始大小為 0,當(dāng)?shù)谝淮螌?xiě)入大小為 10 byte 的字符串時(shí),則會(huì)申請(qǐng)大小為 16 byte 的內(nèi)存(恰好大于 10 byte 的 2 的指數(shù)),第二次寫(xiě)入 10 byte 時(shí),內(nèi)存不夠,則申請(qǐng) 32 byte 的內(nèi)存,第三次寫(xiě)入內(nèi)存足夠,則不申請(qǐng)新的,以此類(lèi)推。在實(shí)際過(guò)程中,超過(guò)一定大小,比如 2048 byte 后,申請(qǐng)策略上會(huì)有些許調(diào)整。

2.2 比較 strings.Builder 和 bytes.Buffer

strings.Builderbytes.Buffer 底層都是 []byte 數(shù)組,但 strings.Builder 性能比 bytes.Buffer 略快約 10% 。一個(gè)比較重要的區(qū)別在于,bytes.Buffer轉(zhuǎn)化為字符串時(shí)重新申請(qǐng)了一塊空間,存放生成的字符串變量,而 strings.Builder 直接將底層的[]byte轉(zhuǎn)換成了字符串類(lèi)型返回了回來(lái)。

總結(jié)

到此這篇關(guān)于Golang字符串拼接的性能以及原理詳解的文章就介紹到這了,更多相關(guān)Golang字符串拼接性能內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文詳解Go語(yǔ)言中Mutex互斥鎖

    一文詳解Go語(yǔ)言中Mutex互斥鎖

    Golang中的Mutex互斥鎖是一種常用的并發(fā)控制機(jī)制,用于保護(hù)共享資源的訪問(wèn),在本文中,我們將深入探討Mutex互斥鎖的原理、日常使用、鎖結(jié)構(gòu)以及運(yùn)行機(jī)制,需要的朋友可以參考下
    2023-12-12
  • Go的固定時(shí)長(zhǎng)定時(shí)器和周期性時(shí)長(zhǎng)定時(shí)器

    Go的固定時(shí)長(zhǎng)定時(shí)器和周期性時(shí)長(zhǎng)定時(shí)器

    本文主要介紹了Go的固定時(shí)長(zhǎng)定時(shí)器和周期性時(shí)長(zhǎng)定時(shí)器,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • golang之?dāng)?shù)據(jù)校驗(yàn)的實(shí)現(xiàn)代碼示例

    golang之?dāng)?shù)據(jù)校驗(yàn)的實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了golang之?dāng)?shù)據(jù)校檢的實(shí)現(xiàn)代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Go語(yǔ)言結(jié)合grpc和protobuf實(shí)現(xiàn)去中心化的聊天室

    Go語(yǔ)言結(jié)合grpc和protobuf實(shí)現(xiàn)去中心化的聊天室

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言如何結(jié)合grpc和protobuf實(shí)現(xiàn)去中心化的聊天室,文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • golang使用http client發(fā)起get和post請(qǐng)求示例

    golang使用http client發(fā)起get和post請(qǐng)求示例

    這篇文章主要介紹了golang使用http client發(fā)起get和post請(qǐng)求示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Go語(yǔ)言開(kāi)發(fā)前后端不分離項(xiàng)目詳解

    Go語(yǔ)言開(kāi)發(fā)前后端不分離項(xiàng)目詳解

    這篇文章主要為大家介紹了Go語(yǔ)言開(kāi)發(fā)前后端不分離項(xiàng)目詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • golang方法中receiver為指針與不為指針的區(qū)別詳析

    golang方法中receiver為指針與不為指針的區(qū)別詳析

    這篇文章主要給大家介紹了關(guān)于golang方法中receiver為指針與不為指針區(qū)別的相關(guān)資料,其實(shí)最大的區(qū)別應(yīng)該是指針傳遞的是對(duì)像的引用,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-10-10
  • Go語(yǔ)言fmt包的具體使用

    Go語(yǔ)言fmt包的具體使用

    Go語(yǔ)言的fmt包提供了豐富多樣的輸入輸出功能,無(wú)論是格式化輸出、文件寫(xiě)入,還是從各種輸入源讀取數(shù)據(jù),都能輕松應(yīng)對(duì),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-07-07
  • Swaggo零基礎(chǔ)入門(mén)教程

    Swaggo零基礎(chǔ)入門(mén)教程

    swagger是一套基于OpenAPI規(guī)范構(gòu)建的開(kāi)源工具,使用RestApi。swagger-ui呈現(xiàn)出來(lái)的是一份可交互式的API文檔,可以直接在文檔頁(yè)面嘗試API的調(diào)用
    2023-01-01
  • Go創(chuàng)建Grpc鏈接池實(shí)現(xiàn)過(guò)程詳解

    Go創(chuàng)建Grpc鏈接池實(shí)現(xiàn)過(guò)程詳解

    這篇文章主要為大家介紹了Go創(chuàng)建Grpc鏈接池實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03

最新評(píng)論

梁山县| 彭水| 湟源县| 潮州市| 宜丰县| 买车| 通化市| 惠东县| 垫江县| 阜宁县| 靖边县| 涞源县| 天峨县| 应用必备| 应用必备| 新平| 湖北省| 景洪市| 本溪| 讷河市| 巴马| 车致| 桑日县| 潼关县| 漠河县| 宁城县| 吉木萨尔县| 祥云县| 会泽县| 台湾省| 遂昌县| 交口县| 紫阳县| 多伦县| 会同县| 大城县| 涟源市| 柳林县| 泰兴市| 县级市| 万山特区|