欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言中for和range的性能比較

 更新時間:2023年07月31日 09:37:06   作者:搬運工李  
這篇文章主要為大家詳細(xì)介紹了Go語言中for和range語句的使用以及性能比較,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下

能GET到的知識點

什么場景使用for和range

1. 從一個遍歷開始

1.1萬能的range遍歷

1.遍歷array/slice/strings

array

package main  
import "fmt"  
func main() {  
    var UserIDList = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}  
    for i, v := range UserIDList {  
        fmt.Println(i, v)  
    }  
}

輸出:

0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

slice

package main  
import "fmt"  
func main() {  
    var UserIDList = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}  
    var UerSlice = UserIDList[:]  
    for i, v := range UerSlice {  
        fmt.Println(i, v)  
    }  
}

輸出:

0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

字符串

func main(){
    var Username = "斑斑磚abc"  
    for i, v := range Username {  
        fmt.Println(i, v)  
    }
}

輸出:

0 26001
3 26001
6 30742
9 97
10 98
11 99

range進行對array、slice類型遍歷一切都正常,但是到了對字符串進行遍歷時這里就出問題了,出問題主要在索引這一塊??梢钥闯鏊饕敲總€字節(jié)的位置,在go語言中的字符串是UTF-8編碼的字節(jié)序列。而不是單個的Unicode字符。遇到中文字符時需要使用多個字節(jié)表示,英文字符一個字節(jié)進行表示,索引0-3表示了一個字符及以此完后。

2.遍歷map

func ByMap() {  
    m := map[string]int{  
    "one": 1,  
    "two": 2,  
    "three": 3,  
    }  
    for k, v := range m {  
        delete(m, "two")  
        m["four"] = 4  
        fmt.Printf("%v: %v\n", k, v)  
    }  
}

輸出:

one: 1
four: 4
three: 3

  • 和切片不同的是,迭代過程中,刪除還未迭代到的鍵值對,則該鍵值對不會被迭代。
  • 在迭代過程中,如果創(chuàng)建新的鍵值對,那么新增鍵值對,可能被迭代,也可能不會被迭代。個人認(rèn)為應(yīng)該是hash的無序性問題
  • 針對 nil 字典,迭代次數(shù)為 0

3.遍歷channel

func ByChannel() {  
    ch := make(chan string)  
    go func() {  
        ch <- "a"  
        ch <- "b"  
        ch <- "c"  
        ch <- "d"  
        close(ch)  
    }()  
    time.Sleep(time.Second)
    for n := range ch {  
        fmt.Println(n)  
    }  
}
  • 針對于range對關(guān)閉channel的遍歷,會直到把元素都讀取完成。
  • 但是在for遍歷會造成阻塞,因為for變量讀取一個關(guān)閉的管道并不會進行退出,而是一直進行等待,但是如果關(guān)閉了會返回一個狀態(tài)值可以根據(jù)該狀態(tài)值判斷是否需要操作

2.for和range之間奇怪的問題

2.1 無限遍歷現(xiàn)象

for

c := []int{1, 2, 3}  
for i := 0; i < len(c); i++ {  
    c = append(c, i)  
    fmt.Println(i)  
}

輸出:

1
2
3
.
.
.
15096
15097
15098
15099
15100
15101
15102
15103
15104

range

c := []int{1, 2, 3}  
for _, v := range c {  
    c = append(c, v)  
    fmt.Println(v)  
}

輸出:

1
2
3

可以看出for循環(huán)一直在永無止境的進行追加元素。 range循環(huán)正常。原因:for循環(huán)的i < len(c)-1都會進行重新計算一次,造成了永遠(yuǎn)都不成立。range循環(huán)遍歷在開始前只會計算一次,如果在循環(huán)進行修改也不會影響正常變量。

2.2 在for和range進行修改操作

for

type UserInfo struct {  
    Name string  
    Age int  
}
var UserInfoList = [3]UserInfo{  
    {Name: "John", Age: 25},  
    {Name: "Jane", Age: 30},  
    {Name: "Mike", Age: 28},  
    }  
for i := 0; i < len(UserInfoList); i++ {  
    UserInfoList[i].Age += i  
}  
fmt.Println(UserInfoList)

輸出:

0
1
2
[{John 25} {Jane 31} {Mike 30}]

range

var UserInfoList = [3]UserInfo{  
    {Name: "John", Age: 25},  
    {Name: "Jane", Age: 30},  
    {Name: "Mike", Age: 28},  
    }  
for i, info := range UserInfoList {  
    info.Age += i  
}  
fmt.Println(UserInfoList)

輸出:

[{John 25} {Jane 30} {Mike 28}]

可以看出for循環(huán)進行修改了成功,但是在range循環(huán)修改失效,為什么呢?因為range循環(huán)返回的是對該值的拷貝,所以修改失效。for循環(huán)修相當(dāng)于進行原地修改了。但如果在for循環(huán)里面進行賦值修改操作,那么修改也會進行失效 具體如下

var UserInfoList = [3]UserInfo{  
    {Name: "John", Age: 25},  
    {Name: "Jane", Age: 30},  
    {Name: "Mike", Age: 28},  
}  
for i := 0; i < len(UserInfoList); i++ {  
    fmt.Println(i)  
    item := UserInfoList[i]  
    item.Age += i  
}  
fmt.Println(UserInfoList)

輸出:

> [{John 25} {Jane 30} {Mike 28}]

3. Benchmark大比拼

主要是針對大類型結(jié)構(gòu)體

type Item struct {  
    id int  
    val [4096]byte  
}

for_test.go

func BenchmarkForStruct(b *testing.B) {  
    var items [1024]Item  
    for i := 0; i < b.N; i++ {  
        length := len(items)  
        var tmp int  
        for k := 0; k < length; k++ {  
            tmp = items[k].id  
        }  
        _ = tmp  
    }  
}
func BenchmarkRangeStruct(b *testing.B) {  
    var items [1024]Item  
    for i := 0; i < b.N; i++ {  
        var tmp int  
        for _, item := range items {  
            tmp = item.id  
        }  
        _ = tmp  
    }  
}

goos: windows
goarch: amd64
pkg: article/02fortest
cpu: AMD Ryzen 5 5600G with Radeon Graphics
BenchmarkForStruct-12            2503378               474.8 ns/op             0 B/op          0 allocs/op
BenchmarkRangeStruct-12             4983            232744 ns/op               0 B/op          0 allocs/op
PASS
ok      article/02fortest       3.268s

可以看出 for 的性能大約是 range600 倍。

為什么會產(chǎn)生這么大呢?

上述也說過,range遍歷會對迭代的值創(chuàng)建一個拷貝。在占據(jù)占用較大的結(jié)構(gòu)時每次都需要進行做一次拷貝,取申請大約4kb的內(nèi)存,顯然是大可不必的。所以在對于占據(jù)較大的結(jié)構(gòu)時,應(yīng)該使用for進行變量操作。

總結(jié)

如何選擇合適的遍歷,在針對與測試場景的情況下,圖便捷可以使用range,畢竟for循環(huán)需要寫一堆的條件,初始值等。但是如果遍歷的元素是個占用大個內(nèi)存的結(jié)構(gòu)的話,避免使用range進行遍歷。且如果需要進行修改操作的話只能用for遍歷來修改,其實range也可以進行索引遍歷的,在本文為寫,讀者可以去嘗試一下。

到此這篇關(guān)于Go語言中for和range的性能比較的文章就介紹到這了,更多相關(guān)Go for range內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go程序的init函數(shù)在什么時候執(zhí)行

    Go程序的init函數(shù)在什么時候執(zhí)行

    在Go語言中,init?函數(shù)是一個特殊的函數(shù),它用于執(zhí)行程序的初始化任務(wù),本文主要介紹了Go程序的init函數(shù)在什么時候執(zhí)行,感興趣的可以了解一下
    2023-10-10
  • Go語言常見錯誤之誤用init函數(shù)實例解析

    Go語言常見錯誤之誤用init函數(shù)實例解析

    Go語言中的init函數(shù)為開發(fā)者提供了一種在程序正式運行前初始化包級變量的機制,然而,由于init函數(shù)的特殊性,不當(dāng)?shù)厥褂盟赡芤鹨幌盗袉栴},本文將深入探討如何有效地使用init函數(shù),列舉常見誤用并提供相應(yīng)的避免策略
    2024-01-01
  • golang 如何用反射reflect操作結(jié)構(gòu)體

    golang 如何用反射reflect操作結(jié)構(gòu)體

    這篇文章主要介紹了golang 用反射reflect操作結(jié)構(gòu)體的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Golang中自定義json序列化時間格式的示例代碼

    Golang中自定義json序列化時間格式的示例代碼

    Go語言作為一個由Google開發(fā),號稱互聯(lián)網(wǎng)的C語言的語言,自然也對JSON格式支持很好,下面這篇文章主要介紹了關(guān)于Golang中自定義json序列化時間格式的相關(guān)內(nèi)容,下面話不多說了,來一起看看詳細(xì)的介紹吧
    2024-08-08
  • GO語言異常處理機制panic和recover分析

    GO語言異常處理機制panic和recover分析

    這篇文章主要介紹了GO語言異常處理機制panic和recover,分析了捕獲運行時發(fā)生錯誤的方法,是非常實用的技巧,需要的朋友可以參考下
    2014-12-12
  • linux下通過go語言獲得系統(tǒng)進程cpu使用情況的方法

    linux下通過go語言獲得系統(tǒng)進程cpu使用情況的方法

    這篇文章主要介紹了linux下通過go語言獲得系統(tǒng)進程cpu使用情況的方法,實例分析了Go語言使用linux的系統(tǒng)命令ps來分析cpu使用情況的技巧,需要的朋友可以參考下
    2015-03-03
  • Golang?分割字符串的實現(xiàn)示例

    Golang?分割字符串的實現(xiàn)示例

    本文主要介紹了Golang?分割字符串的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • golang 設(shè)置web請求狀態(tài)碼操作

    golang 設(shè)置web請求狀態(tài)碼操作

    這篇文章主要介紹了golang 設(shè)置web請求狀態(tài)碼操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang channel死鎖的幾種情況小結(jié)

    Golang channel死鎖的幾種情況小結(jié)

    本文主要介紹了Golang channel死鎖的幾種情況小結(jié),詳細(xì)的介紹了六種情況,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • 詳解Golang中使用map時的注意問題

    詳解Golang中使用map時的注意問題

    Golang中的map是一種數(shù)據(jù)結(jié)構(gòu),它允許你使用鍵值對的形式存儲和訪問數(shù)據(jù),map在Go中是非排序的,提供了高效查找、插入和刪除元素的能力,特別是當(dāng)鍵是不可變類型,本文給大家詳細(xì)介紹了Golang中使用map時的注意問題,需要的朋友可以參考下
    2024-06-06

最新評論