亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

golang寫文件時阻塞了很多goroutine,為什么不創建很多線程?

golang寫文件時阻塞了很多goroutine,為什么不創建很多線程?

Go
UYOU 2021-09-13 14:23:25
正如我們在 go 中所知道的那樣,當 goroutine 必須執行阻塞調用(例如系統調用)或通過 cgo 調用 C 庫時,可能會創建一個線程。一些測試代碼:   package main   import (        "io/ioutil"        "os"        "runtime"        "strconv"    )    func main() {        runtime.GOMAXPROCS(2)        data, err := ioutil.ReadFile("./55555.log")        if err != nil {            println(err)            return        }        for i := 0; i < 200; i++ {            go func(n int) {                for {                    err := ioutil.WriteFile("testxxx"+strconv.Itoa(n), []byte(data), os.ModePerm)                    if err != nil {                        println(err)                        break                    }                }            }(i)        }        select {}    }當我運行它時,它沒有創建很多線程。? =99=[root /root]$ cat /proc/9616/status | grep -i threadThreads:    5有任何想法嗎?
查看完整描述

3 回答

?
慕標5832272

TA貢獻1966條經驗 獲得超4個贊

goroutine 是一個輕量級線程,它不等同于操作系統線程。的語言規范指定它作為一個“相同的地址空間內的控制的獨立并發線程”。

引用 package 的文檔runtime

GOMAXPROCS 變量限制了可以同時執行用戶級 Go 代碼的操作系統線程的數量。代表Go代碼在系統調用中可以阻塞的線程數沒有限制;這些不計入 GOMAXPROCS 限制。

僅僅因為您啟動了 200 個 goroutine,并不意味著將為它們啟動 200 個線程。您設置GOMAXPROCS為 2,這意味著可以同時運行 2 個“活動”goroutine。如果 goroutine 被阻塞(例如 I/O 等待),可能會產生新線程。你沒有提到你的測試文件有多大,你開始的 goroutines 可能寫得太快了。

有效圍棋博客文章將它們定義為:

它們被稱為goroutines是因為現有的術語——線程、協程、進程等——傳達了不準確的內涵。goroutine 有一個簡單的模型:它是一個與同一地址空間中的其他 goroutine 并發執行的函數。它是輕量級的,成本比分配堆棧空間多一點。并且堆棧開始時很小,因此它們很便宜,并且通過根據需要分配(和釋放)堆存儲來增長。

Goroutines 被多路復用到多個 OS 線程上,所以如果一個應該阻塞,例如在等待 I/O 時,其他人繼續運行。它們的設計隱藏了線程創建和管理的許多復雜性。


查看完整回答
反對 回復 2021-09-13
?
ITMISS

TA貢獻1871條經驗 獲得超8個贊

該問題4056只討論如何限制創建實際的線程(未夠程)的數量。


Go 1.2 在commit 665feee 中引入了線程限制管理。


您可以看到一個測試,以檢查是否實際達到了創建的線程數pkg/runtime/crash_test.go#L128-L134:


func TestThreadExhaustion(t *testing.T) {

    output := executeTest(t, threadExhaustionSource, nil)

    want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"

    if !strings.HasPrefix(output, want) {

        t.Fatalf("output does not start with %q:\n%s", want, output)

    }

}

同一個文件有一個創建實際線程的示例(對于給定的 goroutine),使用runtime.LockOSThread():


func testInNewThread(name string) {

    c := make(chan bool)

    go func() {

        runtime.LockOSThread()

        test(name)

        c <- true

    }()

    <-c

}


查看完整回答
反對 回復 2021-09-13
?
胡子哥哥

TA貢獻1825條經驗 獲得超6個贊

我稍微修改了你的程序以輸出一個更大的塊


package main


import (

    "io/ioutil"

    "os"

    "runtime"

    "strconv"

)


func main() {

    runtime.GOMAXPROCS(2)

    data := make([]byte, 128*1024*1024)

    for i := 0; i < 200; i++ {

        go func(n int) {

            for {

                err := ioutil.WriteFile("testxxx"+strconv.Itoa(n), []byte(data), os.ModePerm)

                if err != nil {

                    println(err)

                    break

                }

            }

        }(i)

    }

    select {}

}

然后,這會按您的預期顯示 >200 個線程


$ cat /proc/17033/status | grep -i thread

Threads:    203

所以我認為系統調用在您的原始測試中退出得太快,無法顯示您期望的效果。


查看完整回答
反對 回復 2021-09-13
  • 3 回答
  • 0 關注
  • 541 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號