自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go 語言內(nèi)置 I/O 多路復(fù)用機(jī)制

開發(fā) 前端
本文我們了解到 select? 中的 case? 語句可以讀取 channel?,多個(gè) case 語句僅能其中 1 個(gè)被執(zhí)行。

01 介紹

Go 協(xié)程之間通過 channel 通信,但是 channel 讀寫取決于自身特性,即是否有可寫入緩沖區(qū)、緩沖區(qū)中是否有數(shù)據(jù)、是否已關(guān)閉...

為了檢測(cè) channel 的特性,Go 提供了一個(gè)關(guān)鍵字 select,可用于實(shí)現(xiàn) I/O 多路復(fù)用機(jī)制。

本文我們介紹 Go 關(guān)鍵字 select 的使用方式。

02 使用方式

Go 關(guān)鍵字 select 中包含 case 語句和 default 語句,其中 default 語句可以認(rèn)為是一種特殊的 case 語句。

因?yàn)?nbsp;default 語句不負(fù)責(zé)處理 channel 的讀寫,它可以在 select 中的任意位置,且僅能包含一個(gè) default 語句。在所有 case 語句都不滿足執(zhí)行條件時(shí),default 語句將被執(zhí)行(建議盡量不要省略 default 語句)。

我們通過代碼片段,分別介紹 select 在檢測(cè)到 channel 不同特性時(shí),得到的運(yùn)行結(jié)果。

空 select

接下來,我們閱讀一段代碼。

func main() {
 fmt.Println("Golang 語言開發(fā)棧")
 go func() {
  fmt.Println("Golang 公眾號(hào)")
 }()
}

閱讀上面這段代碼,讀者朋友們認(rèn)為 Go 協(xié)程中的打印語句可以正常輸出嗎?

讀者朋友們?nèi)绻\(yùn)行代碼,會(huì)發(fā)現(xiàn) Go 協(xié)程中的打印語句還沒有執(zhí)行,程序就已經(jīng)退出了,這是因?yàn)?nbsp;main 函數(shù)中的打印語句已經(jīng)執(zhí)行完成,所以會(huì)退出程序。

如果我們希望 Go 協(xié)程中的打印語句也執(zhí)行,可以在 main 函數(shù)中使用 select{} 將 main 阻塞,Go 協(xié)程中的打印語句就有機(jī)會(huì)執(zhí)行了。但是,這會(huì)導(dǎo)致死鎖(可以根據(jù)實(shí)際應(yīng)用場景選擇是否使用)。

無緩沖 channel

接下來,我們?cè)僮x一段可以導(dǎo)致死鎖的代碼:

func main() {
 c := make(chan string)
 DoChannel(c)
}

func DoChannel(c chan string) {
 var receive string
 send := "golang"
 select {
 case receive = <-c:
  fmt.Println(receive)
 case c <- send:
  fmt.Println(send)
 }
}

閱讀上面這段代碼,我們定義一個(gè)函數(shù) DoChannel(),該函數(shù)接收的參數(shù)是一個(gè) string 類型的 channel,函數(shù)體中使用 select 中的兩個(gè) case 語句,分別對(duì)參數(shù)進(jìn)行接收和發(fā)送操作。

運(yùn)行代碼,select 阻塞。

因?yàn)?,我們傳參?nbsp;c 是無緩沖 channel,所以它即不能讀也不能寫,兩個(gè) case 語句都不執(zhí)行,select 陷入阻塞,導(dǎo)致死鎖(此處為了行文,故意沒有 default 語句)。

無數(shù)據(jù),有緩沖channel

我們將上面這段代碼,稍微修改一下,將入?yún)⒌?nbsp;c 改為 1 個(gè)緩沖區(qū)大小的 channel(未寫入數(shù)據(jù))。代碼如下:

func main() {
 c := make(chan string, 1)
 DoChannel(c)
}

運(yùn)行代碼,寫執(zhí)行,讀未執(zhí)行。

即 select 中的對(duì)入?yún)?nbsp;channel 進(jìn)行發(fā)送操作的 case 語句被執(zhí)行,因?yàn)槿雲(yún)?nbsp;c 是一個(gè)有 1 個(gè)緩沖區(qū)大小的 channel,并且該 channel 中還沒有數(shù)據(jù),所以讀取操作的 case 語句沒有讀取到數(shù)據(jù),不滿足執(zhí)行條件。

有緩沖區(qū),已寫滿數(shù)據(jù) channel

我們?cè)傩薷囊幌氯雲(yún)?nbsp;c,將入?yún)⒌?nbsp;c 改為 1 個(gè)緩沖區(qū)大小的 channel,并且寫入字符串 Go。代碼如下:

func main() {
 c := make(chan string, 1)
 c <- "Go"
 DoChannel(c)
}

運(yùn)行代碼,讀執(zhí)行,寫未執(zhí)行。

即 select 中的對(duì)入?yún)?nbsp;channel 進(jìn)行接收操作的 case 語句被執(zhí)行,因?yàn)槿雲(yún)?nbsp;c 是一個(gè)有 1 個(gè)緩沖區(qū)大小,并且已寫滿數(shù)據(jù),所以讀取操作的 case 語句可以讀取到數(shù)據(jù),滿足執(zhí)行條件。

而寫入操作的 case 無法寫入數(shù)據(jù),不滿足執(zhí)行條件。

有緩沖區(qū),有數(shù)據(jù),可寫數(shù)據(jù) channel

最后一種場景是既能讀取也能寫入的 channel,我們修改一下入?yún)?nbsp;c,將入?yún)?nbsp;c 改為 2 個(gè)緩沖區(qū)大小的 channel,其中 1 個(gè)緩沖區(qū)寫入字符串 Go,另外 1 個(gè)緩沖區(qū)還可以寫入數(shù)據(jù)。代碼如下:

func main() {
 c := make(chan string, 2)
 c <- "Go"
 DoChannel(c)
}

通過多次運(yùn)行代碼,會(huì)發(fā)現(xiàn)讀取和寫入的 case 語句都有機(jī)會(huì)執(zhí)行,因?yàn)閮蓚€(gè) case 語句都滿足執(zhí)行條件,但是只能有 1 個(gè) case 語句執(zhí)行,select 會(huì)隨機(jī)執(zhí)行其中 1 個(gè) case 語句。

至此,我們已經(jīng)介紹了 5 種 channel 在 select 中的運(yùn)行結(jié)果。

case 語句中聲明變量

上面的代碼中,我們發(fā)現(xiàn)在兩個(gè) case 語句中,讀操作我們將讀取到的數(shù)據(jù)賦值給變量 receive,實(shí)際上,我們也可以省略變量賦值操作。

如果我們需要將讀取到的數(shù)據(jù),賦值給變量的話,一般建議將讀取 channel 返回的兩個(gè)值全部接收,其中一個(gè)是讀取到的數(shù)據(jù),另外一個(gè)是布爾值,代表 channel 中沒有數(shù)據(jù),并且已被關(guān)閉。代碼如下:

func main() {
 c := make(chan string)
 close(c)
 DoChannelV2(c)
}

func DoChannelV2(c chan string) {
 var (
  receive string
  ok      bool
 )
 select {
 case receive, ok = <-c:
  if !ok {
   fmt.Println("no data")
  } else {
   fmt.Println(receive)
  }
 }
}

閱讀上面這段代碼,我們使用 close 將 c 關(guān)閉。select 中的讀操作 case 語句,可以通過 ok 的值,得到 channel 中沒有數(shù)據(jù),且已被關(guān)閉,不必打印空數(shù)據(jù)。

03 總結(jié)

本文我們了解到 select 中的 case 語句可以讀取 channel,多個(gè) case 語句僅能其中 1 個(gè)被執(zhí)行。

每個(gè) case 語句僅能對(duì) 1 個(gè) channel 進(jìn)行讀寫操作,如果讀操作未讀取到數(shù)據(jù)將陷入阻塞,如果寫操作無法寫入數(shù)據(jù)將陷入阻塞,如果所有 case 語句中的 channel 都陷入阻塞時(shí),select 也會(huì)陷入阻塞。

為了避免 select 陷入阻塞,我們可以使用 default 語句,需要注意的是,default 語句可以在 select 的任意位置,但是僅能包含 1 個(gè),而 case 語句可以包含多個(gè)。

責(zé)任編輯:武曉燕 來源: Golang語言開發(fā)棧
相關(guān)推薦

2023-12-06 07:16:31

Go語言語句

2021-03-17 16:53:51

IO多路

2021-02-10 08:09:48

Netty網(wǎng)絡(luò)多路復(fù)用

2020-10-13 07:51:03

五種IO模型

2021-03-24 08:03:38

NettyJava NIO網(wǎng)絡(luò)技術(shù)

2020-10-14 09:11:44

IO 多路復(fù)用實(shí)現(xiàn)機(jī)

2023-11-08 09:22:14

I/ORedis阻塞

2024-12-30 00:00:05

2021-06-09 19:25:13

IODubbo

2022-08-26 00:21:44

IO模型線程

2019-12-23 14:53:26

IO復(fù)用

2023-01-09 10:04:47

IO多路復(fù)用模型

2023-08-07 08:52:03

Java多路復(fù)用機(jī)制

2011-12-08 10:51:25

JavaNIO

2021-05-31 06:50:47

SelectPoll系統(tǒng)

2009-06-29 18:09:12

多路復(fù)用Oracle

2022-07-11 08:02:15

KafkaSelector

2024-08-08 14:57:32

2023-11-07 08:19:35

IO多路復(fù)用磁盤、

2022-09-12 06:33:15

Select多路復(fù)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)