Go select 死鎖引發的思考

2022-10-01 01:24:12 字數 3133 閱讀 1175

一文引發的延續思考

package main

import (

"fmt"

)func main()

}()fmt.println("the val:", <-ch)

}func getval(i int) int

無論 select 最終選擇了哪個 case,getval() 都會按照原始碼順序執行:getval(1) 和 getval(2),也就是它們必然先輸出:

getval, i= 1

getval, i= 2

package main

import (

"fmt"

"time"

)func talk(msg string, sleep int) <-chan string

}()return ch

}func fanin(input1, input2 <-chan string) <-chan string

} }()

return ch

}func main()

}

每次進入以下 select 語句時:

select
<-input1<-input2都會執行,相應的值是:a x 和 b x(其中 x 是 0-5)。但每次 select 只會選擇其中乙個 case 執行,所以<-input1<-input2的結果,必然有乙個被丟棄了,也就是不會被寫入 ch 中。因此,一共只會輸出 5 次,另外 5 次結果丟掉了。(你會發現,輸出的 5 次結果中,x 比如是 0 1 2 3 4)

而 main 中迴圈 10 次,只獲得 5 次結果,所以輸出 5 次後,報死鎖。

如果改為這樣就一切正常:

select
我的理解:

case ch <- <-input:語句是分成兩段執行的,可以理解為

t := <- input //case選擇還未明確的時候會執行

ch <- t //如果沒有選擇此case,則不執行此語句

並且這是兩條語句,具有先後順序

所以<-input 執行後,沒有選擇此case,<-input的結果就會被丟棄掉,從而導致上述的死鎖問題。

上述提到

無論 select 最終選擇了哪個 case,getval() 都會按照原始碼順序執行:getval(1) 和 getval(2),也就是它們必然先輸出:

getval, i= 1

getval, i= 2

思考一:如果getval()方法執行的時間不同,select的執行時長是取決於執行時間長的,還是時間的總和?

func getval1(i int) int 

func getval2(i int) int

func main()

fmt.println(time.since(begintime))

} }()

time.sleep(time.second * 10)

}

輸出的結果

getval, i= 1

getval, i= 2

3.0015862s

getval, i= 1

getval, i= 2

3.0021938s

getval, i= 1

getval, i= 2

3.0019246s

可以看出來,每次select都會按順序執行case語句,並且select的執行時間為case語句的總和

當然在實際生產中也不會有這種寫法

正確的寫法:

func main() ()

go func() ()

go func()

} }()

for i := 0; i < 2; i++

fmt.println(time.since(begin))

}

輸出結果,此時取決於執行時間最長的getval()

getval, i= 1

1getval, i= 2

22.0020979s

在實際生產中,select語句只用於接受channel中的數值,而不是去執行某一方法

細心的小夥伴已經發現了,上述的寫法有兩個bug

新起協程中,因為for語句導致一直空轉,該協程不會被銷毀

如果ch被close以後,對其傳送資料,會導致panic

加點注釋看看輸出的結果

func main() ()

go func() ()

time.sleep(2 * time.second)

fmt.println("goroutine num", runtime.numgoroutine())

go func()

}()for

} }()

for i := 0; i < 2; i++

close(ch)

fmt.println(time.since(begin))

fmt.println("goroutine num", runtime.numgoroutine())

ch2 <- 1

time.sleep(time.second * 1)

}

輸出的結果

getval, i= 1

getval, i= 2

goroutine num 212

2.0020965s

goroutine num 2

panic err send on closed channel

可以看到,for迴圈的協程並沒有被釋放,並且在後續的ch <-操作中也報出了panic異常

syslog 引發死鎖

主線程在寫 syslog,同時在訊號處理函式中也在寫syslog,當主線程在寫的時候,如果同時觸發了訊號,那麼將會導致死鎖。pstack 4289 0 0x00000036768df9ee in lll lock wait private from lib64 libc.so.6 1 0x00000...

停課引發的思考

快一周沒去機房了,好懷念在在學習的日子,以至於經常夢到自己在設計程式。唉,說到底還是自己太貪玩,沒有珍惜這來之不易的學習環境。當10期大部分人因遲到被禁止進的時候,我們幾個在大大咧咧的學習,甚至連週末兩天都沒有做到按時上課。結果,讓公尺老師動怒,被判了個無期徒刑。失去了才知道珍惜,也好,這樣再次得到...

電梯引發的思考

有了孩子之後,精力確實有限。珍惜現在的所有的所謂的悠閒時光吧。之前在婦幼醫院看過電梯,上面寫著 層層都停,單層停靠,雙層停靠,1 8層停靠,醫院人多滿載後就不開門了。還有我們經常見的高層電梯,低層電梯。我就想閒下來的時候寫個電梯控制的小程式。彌補一下空虛的心靈。夜深人靜的晚上我就在想,如果讓我寫我會...