無緩衝阻塞 chan 雜談

2021-10-01 06:45:23 字數 1476 閱讀 8289

chan類似佇列版管道,無緩衝chan看起來好像是全域性變數,通過它可讓多個goroutine間通訊。 這其實隱含乙個事實,chan阻塞會引發goroutine上下文切換,而切換到哪乙個可執行goroutine由go排程器決定(與阻塞chan相關)。go當前能夠使用的goroutine,必須在其待命佇列中,否則會產生死鎖。

多程序多執行緒都具備上下文切換,即儲存恢復現場的能力。goroutine的上下文切換實現,是在使用者態基礎上進行,只不過它涉及到的資源比執行緒更少,如產生乙個執行緒系統呼叫分配記憶體通常在1m,而goroutine只有2kb,此外在使用暫存器,段位上,goroutine也只需3個左右,而執行緒則通常在10個左右。

go排程器對goroutine的使用配合chan,具有有序性(在高併發訪問物件時,可用chan這種特性讓訪問請求隱性排隊,解決競態問題)。main函式是特殊的入口goroutine,若有阻塞**,執行時runtime會尋找已入佇列的goroutine並在適當的時機呼叫它。chan並不是全域性變數,確切來說它的讀/寫阻塞會觸發當前goroutine執行權轉移,它只是個通訊器。好似打**,必須先知道對方號碼並有連線,才能正常工作,若順序不對,表現在golang中便是死鎖

package main

import (

"fmt"

)func f1(in chan int)

func main()

上述**會產生死鎖,main入口goroutine,通道out產生了傳送阻塞,此時runtime會嘗試排程與out通道讀相關的goroutine執行,但可惜的是,在out <- 2之前,並沒有向go執行器佇列加入與out讀相關的goroutine。換句話而言,f1壓根就沒入隊,沒有執行機會。

package main

import "fmt"

func main()

func f1(in chan int)

上文提到chan類似管道,管道顧名思義一端進一端出,很形象表明了乙個聯結器。go中的chan連線goroutine,游離於眾多goroutine之間,功用性與全域性變數有得一拼。但chan絕對不是全域性變數,乙個全域性變數,可以在同一函式體內重複讀寫,但對無緩衝chan而言是不可以,原因在同一goroutine內對同一chan讀寫時,存在讀或寫阻塞面臨切換上下文,另乙個對應的永遠沒執行機會,如下

package main

import "fmt"

func main()

package main

import "fmt"

func main()

有緩衝通道,意味著在未超過當前通道限制數之前,當前的goroutine是非阻塞,不會發生上下文切換,即當前goroutine的控制權不發生轉移,runtime也就不會去尋求其它相關goroutine執行。

緩衝 與 無緩衝

先看下面的程式 在上面的程式中printf函式列印的字串最後沒有帶換行符,而且最後呼叫了 exit 函式,這導致了最後沒有列印出 hello world 下面先介紹幾種緩衝機制 1 全緩衝 全緩衝指的是系統在填滿標準io緩衝區之後才進行實際的io操作 注意,對於駐留在磁碟上的檔案來說通常是由標準io...

標準I O緩衝 全緩衝 行緩衝 無緩衝

說明 我只對網路資源進行了整合,方便學習 基於流的操作最終會呼叫read或者write函式進行i o操作。為了使程式的執行效率最高,流物件通常會提供緩衝區,以減少呼叫系統i o庫函式的次數。基於流的i o提供以下3種緩衝 全緩衝 直到緩衝區被填滿,才呼叫系統i o函式。對於讀操作來說,直到讀入的內容...

標準I O緩衝 全緩衝 行緩衝 無緩衝

某日一朋友寫了乙個hello world 出不來結果,如下 include intmain int argc,char argv 注意到,在 中printf語句列印的字串最後沒有帶換行符,而且最後呼叫了 exit函式,這導致了在終端螢幕上顯示不出來字串 hello world 首先介紹一下unix裡...