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

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

為什么互斥體代碼會停止另一個完整的 go-routine?

為什么互斥體代碼會停止另一個完整的 go-routine?

Go
慕斯709654 2021-12-20 16:44:17
var m *sync.RWMutexfunc main() {    m = new(sync.RWMutex)    n := 100    go func() {        for i := 0; i < n; i++ {            write("WA", i)        }    }()    go func() {        for i := 0; i < n; i++ {            write("WB", i)        }    }()    select {}}func write(tag string, i int) {    m.Lock()    fmt.Printf("[%s][%s%d]write start \n", tag, tag, i)    time.Sleep(100 * time.Millisecond)    fmt.Printf("[%s][%s%d]write end \n", tag, tag, i)    m.Unlock()    // time.Sleep(1 * time.Millisecond)}結果在控制臺:go run mutex.go[WB][WB0]寫開始[WB][WB0]寫結束[WB][WB1]寫開始[WB][WB1]寫結束[WB][WB2]寫開始[WB][WB2] ]write end[WB][WB3]write start[WB][WB3]write end[WB][WB4]write start[WB][WB4]write end[WB][WB5]write start[WB][WB5]write end[WB][WB6]寫入開始[WB][WB6]寫入結束[WB][WB7]寫入開始[WB][WB7]寫入結束[WB][WB8]寫入開始[WB][WB8]寫入結束[ WB][WB9]寫開始[WB][WB9]寫結束...> go versiongo version go1.5.2 windows/amd64問題是:為什么“[WA]”的go-routine沒有機會?為什么互斥體代碼會停止另一個完整的 go-routine?我知道一定有關于它的故事或理論。請給我一個閱讀和學習的網址。
查看完整描述

3 回答

?
慕婉清6462132

TA貢獻1804條經驗 獲得超2個贊

Go 使用協作式多任務處理;它不使用搶占式多任務處理:計算機多任務處理。您需要讓調度程序有機會在鎖之間運行。例如,通過調用 Gosched(),


package main


import (

    "fmt"

    "runtime"

    "sync"

    "time"

)


var m *sync.RWMutex


func main() {

    m = new(sync.RWMutex)

    n := 100

    go func() {

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

            write("WA", i)

        }

    }()


    go func() {

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

            write("WB", i)

        }

    }()


    select {}

}


func write(tag string, i int) {

    m.Lock()

    fmt.Printf("[%s][%s%d]write start \n", tag, tag, i)

    time.Sleep(100 * time.Millisecond)

    fmt.Printf("[%s][%s%d]write end \n", tag, tag, i)

    m.Unlock()

    runtime.Gosched()

}

輸出:


[WB][WB0]write start 

[WB][WB0]write end 

[WA][WA0]write start 

[WA][WA0]write end 

[WB][WB1]write start 

[WB][WB1]write end 

[WA][WA1]write start 

[WA][WA1]write end 

[WB][WB2]write start 

[WB][WB2]write end 

[WA][WA2]write start 

[WA][WA2]write end 

[WB][WB3]write start 

[WB][WB3]write end 

[WA][WA3]write start 

[WA][WA3]write end 


查看完整回答
反對 回復 2021-12-20
?
嗶嗶one

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

這種情況稱為活鎖。

當你調用m.Unlock()即使兩個 goroutines(A 和 B)正在等待這個鎖被釋放時,調度程序可以自由地喚醒它們中的任何一個以繼續。

看起來 Go 中調度程序的當前實現并沒有快速切換到 goroutine A 以使其足以獲取互斥鎖。在這發生之前,goroutine B 重新獲取互斥鎖。

正如您可能發現的那樣,如果您在time.Sleep調用后移動調用m.UnlockA 和 B goroutines 將同時運行。

希望這是有道理的。


查看完整回答
反對 回復 2021-12-20
?
慕村225694

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

只是為了詳細說明調度,該for循環是一個順序緊密循環。意味著來自該循環的編譯指令將占用整個線程來完成。同時,低級指令的其他位將阻塞,除非它們在循環runtime.Gosched()中間有一些由或 sleep提供的調度周期。這就是為什么他們實際上沒有機會了解sync.Mutex(順便說一句,兩者都應該sync.Mutex在聲明和實例化時):


go func() {

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

        runtime.Gosched()

        write("WA", i)

    }

}()


go func() {

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

        runtime.Gosched()

        write("WB", i)

    }

}()

并且 Go 調度程序在指令級別(如 Erlang)不是搶占式的。這就是為什么最好使用通道來編排執行路徑的原因。


注意:我通過艱難的方式(不是低級 Go 編譯器專家)學到了這一點。通道以更干凈的方式在 Go-Routines(和那些額外的周期)上提供編排。換句話說,sync.Mutex應該僅用于監督對事物的訪問;不是為了編排。


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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