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

解決Golang中g(shù)oroutine執(zhí)行速度的問題

 更新時間:2021年05月01日 14:36:57   作者:Lazyboy_Chen7  
這篇文章主要介紹了解決Golang中g(shù)oroutine執(zhí)行速度的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

突然想到了之前一直沒留意的for循環(huán)中開goroutine的執(zhí)行順序問題,就找了段代碼試了試,試了幾次后發(fā)現(xiàn)幾個有意思的地方,我暫時沒有精力往更深處挖掘,希望有g(shù)olang大神能簡單說一說這幾個地方是怎么回事。

代碼:

package main  
import "fmt" 
func Count(ch chan int) {
	fmt.Println("Count doing")
	ch <- 1
	fmt.Println("Counting")
}
 
func main() {
    chs := make([]chan int, 100)
	for i := 0; i < 100; i++ {
		chs[i] = make(chan int)
		go Count(chs[i])
		fmt.Println("Count",i)
	}
	for i, ch := range chs {
		<-ch
		fmt.Println("Counting ", i)
	}
} 

試了幾次之后,反復(fù)的想goroutine執(zhí)行的問題。

根據(jù)下面的輸出,我能看到的是:

1. for循環(huán)的速度 比 for中開出goroutine并執(zhí)行的速度 執(zhí)行的快

2. 但是 開goroutine和執(zhí)行第一個fmt的速度可能趕上 for循環(huán)的速度 比如前12個count和count doing

3. 關(guān)鍵問題,第二個for循環(huán)執(zhí)行的fmt竟然要比goroutine中的第二個fmt快??(放入channel很耗時?)

4. main結(jié)束時,也就是第二個for循環(huán)結(jié)束時, 還有g(shù)oroutine中的第二個fmt沒執(zhí)行

輸出:

Count 0
Count 1
Count 2
Count 3
Count 4
Count 5
Count 6
Count 7
Count 8
Count 9
Count 10
Count 11
Count doing
Count doing
Count doing
Count doing
Count doing
Count 12
Count doing
Count doing
Count doing
Count doing
Count doing
Count doing
Count doing
Count 13
Count 14
Count 15
Count 16
Count 17
Count 18
Count 19
Count 20
Count 21
Count doing
Count doing
Count doing
Count 22
Count doing
Count doing
Count doing
Count 23
Count 24
Count 25
Count 26
Count 27
Count 28
Count 29
Count 30
Count doing
Count 31
Count doing
Count doing
Count 32
Count 33
Count 34
Count 35
Count doing
Count 36
Count doing
Count doing
Count 37
Count 38
Count doing
Count doing
Count doing
Count doing
Count 39
Count 40
Count 41
Count 42
Count 43
Count doing
Count doing
Count 44
Count 45
Count 46
Count 47
Count doing
Count 48
Count 49
Count doing
Count doing
Count 50
Count 51
Count doing
Count doing
Count doing
Count doing
Count doing
Count 52
Count 53
Count doing
Count doing
Count doing
Count doing
Count 54
Count doing
Count 55
Count 56
Count 57
Count 58
Count 59
Count 60
Count 61
Count 62
Count 63
Count 64
Count 65
Count doing
Count doing
Count doing
Count 66
Count 67
Count 68
Count 69
Count doing
Count 70
Count doing
Count 71
Count 72
Count doing
Count 73
Count doing
Count doing
Count 74
Count doing
Count 75
Count 76
Count 77
Count doing
Count doing
Count doing
Count doing
Count 78
Count 79
Count 80
Count 81
Count 82
Count 83
Count 84
Count 85
Count 86
Count 87
Count 88
Count 89
Count 90
Count 91
Count 92
Count 93
Count 94
Count doing
Count doing
Count doing
Count doing
Count doing
Count doing
Count doing
Count doing
Count 95
Count doing
Count 96
Count doing
Count 97
Count 98
Count doing
Count 99
Count doing
Count doing
Counting  0
Counting  1
Counting  2
Counting  3
Counting  4
Counting  5
Counting  6
Count doing
Count doing
Counting  7
Counting  8
Count doing
Counting
Count doing
Counting  9
Counting
Count doing
Count doing
Count doing
Count doing
Count doing
Counting
Count doing
Count doing
Count doing
Counting
Count doing
Counting
Count doing
Counting  10
Counting  11
Counting
Count doing
Count doing
Count doing
Count doing
Count doing
Count doing
Counting
Count doing
Count doing
Counting
Counting
Count doing
Count doing
Count doing
Count doing
Counting
Count doing
Counting
Count doing
Count doing
Counting  12
Counting  13
Counting  14
Counting  15
Counting  16
Counting  17
Counting  18
Counting  19
Counting  20
Counting  21
Counting  22
Counting  23
Counting  24
Counting  25
Counting  26
Counting  27
Counting  28
Counting  29
Counting  30
Counting  31
Counting  32
Counting  33
Counting  34
Counting  35
Counting  36
Counting  37
Counting  38
Counting  39
Counting  40
Counting  41
Counting  42
Counting  43
Counting  44
Counting  45
Counting  46
Counting  47
Counting  48
Counting  49
Counting  50
Counting  51
Counting  52
Counting  53
Counting  54
Counting  55
Counting  56
Counting
Counting
Counting
Counting
Counting
Counting
Count doing
Counting
Count doing
Counting
Counting
Counting  57
Counting  58
Counting  59
Counting  60
Counting  61
Counting  62
Counting  63
Counting  64
Counting  65
Counting  66
Counting  67
Counting  68
Counting  69
Counting  70
Counting  71
Counting  72
Counting  73
Counting  74
Counting  75
Counting  76
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting
Counting  77
Counting  78
Counting  79
Counting  80
Counting  81
Counting  82
Counting  83
Counting  84
Counting  85
Counting  86
Counting  87
Counting  88
Counting  89
Counting  90
Counting  91
Counting  92
Counting  93
Counting  94
Counting  95
Counting  96
Counting  97
Counting  98
Counting  99

補充:【golang】goroutine調(diào)度的坑

今天說說我遇到的一個小坑, 關(guān)于goroutine 調(diào)度的問題。

關(guān)于goroutine的調(diào)度,網(wǎng)上資料已經(jīng)一大堆了,這里就不再贅述了。

還是簡單的說一下我理解的goroutine的調(diào)度。goroutine是語言層面的,它和內(nèi)核線程是M:N的關(guān)系,并且用了分段棧,是相當輕量了。

如果設(shè)置runtime.GOMAXPROCS為1,那么會有一個上下文G,在G上會有一個對應(yīng)的內(nèi)核線程M,內(nèi)核線程M上可以對應(yīng)很多個goroutine記作G,每個上下文都會有一個隊列稱作runqueue,在用go關(guān)鍵字開啟一個goroutine的時候,該goroutine就會被裝入runqueue中,然后被M用來執(zhí)行,如果剛好有兩個goroutine在隊列里,先執(zhí)行的goroutine因為執(zhí)行一些耗時操作(系統(tǒng)調(diào)用,讀寫 channel,gosched 主動放棄,網(wǎng)絡(luò)IO)會被掛起(扔到全局runqueue),然后調(diào)度后面的goroutine。

好,重點在這里,看一下下面的一段代碼

func main(){
    runtime.GOMAXPROCS(1)
    waitGroup.Add(1)
    go func(){
        defer waitGroup.Done()
        for i := 0;i < 20;i++ {
            fmt.Println("hello")
            f, _ := os.Open("./data")
            f.Write([]byte("hello"))
        }
    }()
    waitGroup.Add(1)
    go func(){
        defer waitGroup.Done()
        for {
        }
    }()
    waitGroup.Wait()
}

這段代碼你運行,你會發(fā)現(xiàn),永遠都會被阻塞住,hello永遠都打印不出來

好,這里出現(xiàn)了兩個問題

1.為什么死循環(huán)的goroutine總是先運行?按理說不應(yīng)該是隨機的嗎?

2.為什么死循環(huán)的goroutine會阻塞而沒有被掛起?

先看第二個問題。這里的話,我當時也很苦惱,于是在網(wǎng)上發(fā)了問題,得到的回復(fù)是,死循環(huán)不屬于上述任何一種需要被掛起的狀態(tài),于是死循環(huán)的goroutine會一直運行,想象一個高并發(fā)的場景,如果其中一個goroutine因為某種原因陷入死循環(huán)了,當前執(zhí)行這個goroutine的OS thread基本就會被一直執(zhí)行這個goroutine,直到程序結(jié)束,這簡直是一場災(zāi)難。但是,1.12 會修正這個小問題。我們還是默默的等待新版本發(fā)布吧。

再看第一個問題。為什么死循環(huán)的goroutine總是先運行?按理說不應(yīng)該是隨機的嗎?測試過很多次,都是第二個goroutine先運行。嗯,其實就算是第二個goroutine先運行也是具有隨機性的,這關(guān)于golang的編譯器如何去實現(xiàn)隨機??匆幌麓罄械幕卮?:

<不是說測試很多遍它就會一直這樣,語言規(guī)范沒有說必須是這個順序,那編譯器怎么實現(xiàn)都可以,因為都不違反規(guī)范。

所以你要把它看作是隨機的,不能依賴這種未確定的行為,不然很可能新版的編譯器就會破壞你依賴的事實。有些項目不敢升級編譯器版本,就是因為依賴了特定版本的編譯器的行為,一升級就壞了。

不是你自己測試很多遍你就能依賴它,編譯器、操作系統(tǒng)、硬件等等不同,都有可能出現(xiàn)不同的結(jié)果??梢砸蕾嚨闹挥姓Z言規(guī)范( https://golang.org/ref/spec ),編譯器實現(xiàn)者是一定會遵守的。

到這里也算是解決了上述的兩個問題了。

來看一下另外一個版本

func main(){
    runtime.GOMAXPROCS(1)
    waitGroup.Add(1)
    go func(){
        defer waitGroup.Done()
        for {
        }
    }()
    waitGroup.Add(1)
    go func(){
        defer waitGroup.Done()
        for i := 0;i < 20;i++ {
            fmt.Println("hello")
            f, _ := os.Open("./data")
            f.Write([]byte("hello"))
            http.Get("http://www.baidu.com")
            fmt.Println("request successful")
        }
    }()
    waitGroup.Wait()
}

執(zhí)行結(jié)果是,會先打印一個hello,然后陷入死循環(huán),這也是說明了goroutine在遇到耗時操作或者系統(tǒng)調(diào)用的時候,后面的代碼都不會執(zhí)行了(request successful 沒有被打?。?,會被拋到全局runqueue里去,然后執(zhí)行runqueue中等待的goroutine

希望能夠幫助和我一樣正在學(xué)習(xí)golang的友軍們更好的理解goroutine的調(diào)度問題

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • golang 熔斷限流降級實踐

    golang 熔斷限流降級實踐

    本文主要介紹了golang 熔斷限流降級實踐,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • 關(guān)于golang類型推斷和變量重聲明詳解

    關(guān)于golang類型推斷和變量重聲明詳解

    在Go語言中,類型推斷可以根據(jù)變量的初始化值自動推斷出變量的類型,而不需要顯式地聲明變量類型,變量重聲明可以在同一作用域內(nèi)重復(fù)聲明一個變量,只要其中至少一個是新的變量,本就簡單的給大家介紹一下golang類型推斷和變量重聲明,需要的朋友可以參考下
    2023-08-08
  • Golang實踐之Error創(chuàng)建和處理詳解

    Golang實踐之Error創(chuàng)建和處理詳解

    在 C#、Java 等語言中常常使用 try...catch的方式來捕獲異常,但是在Golang 對于錯誤處理有不同的方式,像網(wǎng)上也有很多對 error 處理的最佳實踐的文章,其中很多其實就是對 error 的統(tǒng)一封裝,使用規(guī)范進行約束,本文主要是記錄自己對處理 Error 的一些認識和學(xué)習(xí)
    2023-09-09
  • Go語言實現(xiàn)定時器的方法

    Go語言實現(xiàn)定時器的方法

    這篇文章主要介紹了Go語言實現(xiàn)定時器的方法,涉及Go語言時間操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • golang中的select關(guān)鍵字用法總結(jié)

    golang中的select關(guān)鍵字用法總結(jié)

    這篇文章主要介紹了golang中的select關(guān)鍵字用法總結(jié),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • golang實現(xiàn)ftp實時傳輸文件的案例

    golang實現(xiàn)ftp實時傳輸文件的案例

    這篇文章主要介紹了golang實現(xiàn)ftp實時傳輸文件的案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang使用DuckDB查詢Parquet文件數(shù)據(jù)的操作代碼

    Golang使用DuckDB查詢Parquet文件數(shù)據(jù)的操作代碼

    本文介紹DuckDB查詢Parquet文件的典型應(yīng)用場景,掌握DuckDB會讓你的產(chǎn)品分析能力更強,相反系統(tǒng)運營成本相對較低,為了示例完整,我也提供了如何使用Python導(dǎo)出MongoDB數(shù)據(jù),需要的朋友可以參考下
    2025-01-01
  • 基于go實例網(wǎng)絡(luò)存儲協(xié)議詳解

    基于go實例網(wǎng)絡(luò)存儲協(xié)議詳解

    這篇文章主要為大家介紹了基于go實例網(wǎng)絡(luò)存儲協(xié)議詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Go Java算法之二叉樹的所有路徑示例詳解

    Go Java算法之二叉樹的所有路徑示例詳解

    這篇文章主要為大家介紹了Go Java算法之二叉樹的所有路徑示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • golang使用viper解析配置文件的示例代碼

    golang使用viper解析配置文件的示例代碼

    Viper是一個輕量級的、易于使用的配置工具庫,它允許你在Go應(yīng)用中方便地管理配置,Viper支持從多種來源讀取配置,如環(huán)境變量、命令行參數(shù)、文件、甚至是加密的數(shù)據(jù)存儲,本文給大家介紹了golang使用viper解析配置文件,需要的朋友可以參考下
    2024-08-08

最新評論

丹寨县| 辽宁省| 南投县| 确山县| 北流市| 上杭县| 通山县| 宣城市| 怀集县| 辽中县| 崇明县| 望江县| 勃利县| 新河县| 长治县| 策勒县| 阳城县| 临城县| 礼泉县| 普安县| 濮阳县| 浙江省| 云和县| 辽中县| 云林县| 娄底市| 中西区| 峨边| 资讯 | 紫金县| 贵南县| 织金县| 沂源县| 巍山| 宁津县| 商丘市| 金门县| 吴川市| 南溪县| 四子王旗| 吴忠市|