亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Golang中channel的用法舉例詳解

 更新時(shí)間:2025年06月11日 08:32:25   作者:水草  
Channel是Golang的2大核心之一,類似Linux的管道,為并發(fā)Goroutine提供一種同步通信機(jī)制,借助于Channel不同的Goroutine之間可以相互通信,這篇文章主要介紹了Golang中channel用法的相關(guān)資料,需要的朋友可以參考下

前言

在golang并發(fā)編程實(shí)踐中,channel的正確運(yùn)用直接影響程序的健壯性和執(zhí)行效率。本文將深入探討幾種提升channel使用效能的典型場(chǎng)景與實(shí)現(xiàn)策略。

1.channel的類別

主要有2種:

有緩存 Channel(buffered channel),使用 make(chan type, capacity int) 創(chuàng)建
無(wú)緩存 Channel(unbuffered channel),使用 make(chan type) 創(chuàng)建
其中 ,type為 Channel 傳遞數(shù)據(jù)的類型,capacity 為緩存大小。

unbuffered channel:阻塞、同步模式

  • sender端向channel中send一個(gè)數(shù)據(jù),然后阻塞,直到receiver端將此數(shù)據(jù)receive
  • receiver端一直阻塞,直到sender端向channel發(fā)送了一個(gè)數(shù)據(jù)

buffered channel:非阻塞、異步模式

  • sender端可以向channel中send多個(gè)數(shù)據(jù)(只要channel容量未滿),容量滿之前不會(huì)阻塞
  • receiver端按照隊(duì)列的方式(FIFO,先進(jìn)先出)從buffered channel中按序receive其中數(shù)據(jù)

2.channel的狀態(tài)

主要有3種狀態(tài):

  • actived,正常狀態(tài),可以正常的讀receive,寫send
  • nil,未初始化狀態(tài),即只進(jìn)行了聲明但還尚未分配內(nèi)存,或者是channel被主動(dòng)賦值為了nil
  • closed,關(guān)閉狀態(tài)。 注意:channel被close后,它的狀態(tài)并不是nil。因?yàn)閚il channel是不能讀取的,會(huì)panic。但是close后的channel,如果管道里還有數(shù)據(jù),是可以通過(guò)range正常讀取出來(lái)的。

3.channel的操作

常用的操作有這4種:

  • 讀,<- ch
  • 寫,ch <-
  • 關(guān)閉, close(ch)
  • 遍歷,for v := range ch {}

4.組合操作

前面所說(shuō)的3種狀態(tài),和4種操作,組合起來(lái)后的結(jié)果如下:

操作\狀態(tài)activedclosenil
<-ch (讀)成功或者阻塞零值死鎖
ch<- (寫)成功或者阻塞panic死鎖
close成功panic(重復(fù)關(guān)閉)panic
for range成功成功(break)死鎖

有2個(gè)特殊點(diǎn)需要說(shuō)明:

4.1 for range closed_chan

場(chǎng)景1:channel已關(guān)閉且無(wú)剩余數(shù)據(jù)循環(huán)立即退出:如果channel在關(guān)閉時(shí)已經(jīng)沒(méi)有數(shù)據(jù),for range循環(huán)不會(huì)執(zhí)行任何迭代,直接終止。

ch := make(chan int)
close(ch)
for v := range ch { // 循環(huán)不執(zhí)行,直接退出
    // 代碼不會(huì)執(zhí)行
}

場(chǎng)景2:channel已關(guān)閉但有剩余數(shù)據(jù)讀取所有數(shù)據(jù)后退出:如果channel關(guān)閉時(shí)仍有數(shù)據(jù)未被讀取,for range會(huì)讀取所有剩余數(shù)據(jù),然后正常退出循環(huán)。

ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
for v := range ch { 
    fmt.Println(v) // 輸出1、2
}

場(chǎng)景3:未關(guān)閉的Channel會(huì)導(dǎo)致阻塞如果channel未關(guān)閉且無(wú)數(shù)據(jù),for range會(huì)一直阻塞等待數(shù)據(jù),可能導(dǎo)致goroutine泄漏。

4.2 nil channel在select中的行為

如上面的表格所展示:對(duì)nil channel進(jìn)行讀寫,都會(huì)導(dǎo)致死鎖(永久阻塞)。
無(wú)論是發(fā)送(ch <- v)還是接收(<- ch),操作nil channel的代碼會(huì)永久阻塞。

var ch chan int // ch是nil
ch <- 1         // 永久阻塞(發(fā)送到nil channel)
<-ch            // 永久阻塞(從nil channel接收)

但是,如果是在select中,則select會(huì)忽略nil channel的case:

  • 當(dāng)select的某個(gè)case操作的是nil channel時(shí),該case會(huì)被視為未就緒,直接跳過(guò)。
  • 如果其他case中有就緒的channel操作,select會(huì)正常執(zhí)行這些case。
  • 如果所有case都未就緒(包括nil channel的case),且沒(méi)有default分支,則select會(huì)阻塞等待,但不會(huì)觸發(fā)死鎖(除非整個(gè)goroutine再無(wú)其他代碼可執(zhí)行)。

場(chǎng)景1:nil channel與其他有效case共存

var ch chan int // ch是nil
timeout := time.After(1 * time.Second)

select {
case <-ch: // 該case被跳過(guò)(nil channel)
    fmt.Println("Received from ch")
case <-timeout:
    fmt.Println("Timeout") // 1秒后執(zhí)行
}

結(jié)果:select會(huì)忽略<-ch(nil channel),等待timeout就緒后執(zhí)行。
不會(huì)死鎖:因?yàn)榇嬖谄渌行ase(timeout)。

場(chǎng)景2:所有case均為nil channel

var ch1, ch2 chan int // 均為nil
select {
case <-ch1: // 被跳過(guò)
case <-ch2: // 被跳過(guò)
}

結(jié)果:select會(huì)永久阻塞,但如果整個(gè)goroutine沒(méi)有其他代碼可執(zhí)行,會(huì)觸發(fā)死鎖(fatal error: all goroutines are asleep - deadlock!)。
關(guān)鍵點(diǎn):死鎖是否發(fā)生取決于整個(gè)goroutine的狀態(tài),而不僅僅是select本身。

select的設(shè)計(jì)機(jī)制:

  • select會(huì)動(dòng)態(tài)檢查所有case的就緒狀態(tài),跳過(guò)未就緒的case(包括nil channel)。
  • 只要存在其他就緒的case(如定時(shí)器、非nil channel等),select就能正常執(zhí)行。

5.channel常見(jiàn)用法

5.1 使用for range讀取channel

場(chǎng)景:需要持續(xù)不斷從channel讀取數(shù)據(jù)

說(shuō)明:采用range關(guān)鍵字進(jìn)行通道遍歷,當(dāng)發(fā)送端關(guān)閉通道時(shí),循環(huán)自動(dòng)終止。這種方式避免了手動(dòng)檢測(cè)通道狀態(tài)的繁瑣操作,同時(shí)保證不會(huì)讀取到無(wú)效零值。

示例:

for v := range ch{
    doSomething(v)
}

5.2 使用_, ok判斷channel狀態(tài)

場(chǎng)景:雙返回值驗(yàn)證機(jī)制,用于讀取channel但不確定channel是否已經(jīng)關(guān)閉

說(shuō)明:當(dāng)不確定通道是否關(guān)閉時(shí),采用特殊語(yǔ)法進(jìn)行安全校驗(yàn)。返回值狀態(tài)指示符ok為true表示成功接收有效數(shù)據(jù),false則標(biāo)志通道已關(guān)閉。

示例:

if v, ok := <-ch; ok {
    doSomething(v)
}

5.3 使用select進(jìn)行多路channel處理

場(chǎng)景:選擇性路由機(jī)制。select對(duì)多個(gè)channel同時(shí)處理時(shí),會(huì)先處理最先發(fā)生的channel

說(shuō)明:當(dāng)需要同時(shí)監(jiān)聽(tīng)多個(gè)數(shù)據(jù)源時(shí),select語(yǔ)句可實(shí)現(xiàn)智能路由。注意nil channel的特殊處理,讀取會(huì)永久阻塞,寫入將導(dǎo)致運(yùn)行時(shí)異常,但是注意4.2節(jié)中提到的select對(duì)于nil channel的特殊情況。

示例:

select {
case taskCh <- newTask:
    processTask()
case <-shutdownSignal:
    terminate()
}

5.4 使用channel控制讀寫權(quán)限

場(chǎng)景:協(xié)程對(duì)某個(gè)channel只讀或者只寫時(shí)

說(shuō)明:通過(guò)聲明只讀/只寫類型channel,增強(qiáng)代碼可維護(hù)性。這種類型約束可防止意外的反向操作,降低運(yùn)行時(shí)panic風(fēng)險(xiǎn)。

示例:

// 只寫操作
func writeOnly(n int)  <-chan int {
    ch := make(chan int)
    go func() {
      defer close(ch) //必須關(guān)閉channel以通知外面的其它工作協(xié)程退出.
                      //不然,在外面無(wú)法close一個(gè)單向的channel,導(dǎo)致死鎖
      for i:=0; i<n; i++ {
          ch <- i
      }
    }()
    return out
}
// 只讀操作
func readOnly(in <-chan int) {
    for v := range in {
        doSomething(v)
    }
}

5.5 使用channel進(jìn)行并發(fā)控制

場(chǎng)景:同步,異步和并發(fā)調(diào)用

說(shuō)明:有緩存chan(buffered channel)是異步的,可提供給多個(gè)協(xié)程同時(shí)處理,提高系統(tǒng)的并發(fā)性能。而無(wú)緩存chan(unbuffered channel)是同步的。

// 有緩存channel
ch1 := make(chan int, 1)
// 無(wú)緩存channel
ch2 := make(chan int)
ch3 := make(chan int, 0)

示例: 并發(fā)處理模型

func doWorker(inCh <-chan int, outCh chan<- int, wg *sync.WaitGroup) {
	defer wg.Done()
	for v := range inCh {
		outCh <- v * 10
	}
}

func concurrentProcess() {
	inCh := writeOnly(100)
	outCh := make(chan int, 10)
	var wg sync.WaitGroup

	// 同時(shí)運(yùn)行5個(gè)協(xié)程,從inCh中并發(fā)讀取數(shù)據(jù),并發(fā)寫入outCh
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go doWorker(inCh, outCh, &wg)
	}

	//等待所有worker完成并關(guān)閉outCh
	go func() {
		wg.Wait()
		close(outCh)
	}()

	for v := range outCh {
		fmt.Println(v)
	}
}

5.6 超時(shí)控制

場(chǎng)景:在一些需要進(jìn)行超時(shí)控制的情況下

說(shuō)明:通過(guò)結(jié)合定時(shí)器(select & time.After)實(shí)現(xiàn)操作時(shí)效控制,避免長(zhǎng)期阻塞。特別注意定時(shí)channel的資源釋放問(wèn)題。

示例:

func doWorker() <-chan int {
	ch := make(chan int)
	go func() {
		// do something for ch
	}()
	return ch
}
	
func doWithTimeout(timeout time.Duration) (int, error) {
	select {
	case v := <-doWorker2():
		return v, nil
	case <-time.After(timeout):
		return 0, fmt.Errorf("timeout")
	}
}

func main() {
	v, err := doWithTimeout(1 * time.Second)
	fmt.Printf("v:%d, err:%v\n", v, err)
}

輸出: v:0, err:timeout

5.7 非阻塞讀寫channel

場(chǎng)景:對(duì)channel進(jìn)行非阻塞式的讀或者寫

說(shuō)明:通過(guò)default分支實(shí)現(xiàn)即時(shí)返回,適用于不可阻塞的實(shí)時(shí)系統(tǒng)。需要與帶緩沖通道配合使用。

示例:

非阻塞的立即返回方案

func unblockWrite(ch chan int, v int) error {
	select {
	case ch <- v:
		return nil
	default:
		return fmt.Errorf("channel write blocked")
	}
}

func unblockRead(ch chan int) (int, error) {
	select {
	case v := <-ch:
		return v, nil
	default:
		return 0, fmt.Errorf("channel read blocked")
	}
}

5.8 級(jí)聯(lián)close channel

場(chǎng)景:進(jìn)行優(yōu)雅關(guān)閉,廣播通知所有協(xié)程退出

說(shuō)明:關(guān)閉channel會(huì)產(chǎn)生廣播效應(yīng),所有接收此channel的協(xié)程都會(huì)收到零值。結(jié)合sync.WaitGroup可實(shí)現(xiàn)安全終止。

示例:

type Manager struct {
	stopCh chan struct{}
	workCh chan struct{}
	wg     sync.WaitGroup
}

func (m *Manager) Shutdown() {
	close(m.stopCh)
	//等待所有其它協(xié)程退出
	m.wg.Wait()
}

func (m *Manager) workLoop() {
	for {
		select {
		case v := <-m.workCh:
			go doWorker(v)
		case <-m.stopCh:  //close后會(huì)讀取到零值
			return
		}
	}
}

5.9 信號(hào)事件載體

場(chǎng)景:定義的channel,僅用來(lái)傳遞事件/信號(hào),無(wú)需傳遞數(shù)據(jù)

說(shuō)明:當(dāng)僅需事件通知而不傳遞數(shù)據(jù)時(shí),采用空結(jié)構(gòu)體通道可最小化內(nèi)存消耗。

示例:在5.8節(jié)中,stopCh就是用于事件傳遞的channel。它并不需要傳遞數(shù)據(jù),只需要向其它的所有協(xié)程發(fā)出終止信號(hào)。

5.10高效數(shù)據(jù)傳輸

場(chǎng)景:用于性能優(yōu)化,傳遞指針,而非拷貝數(shù)據(jù)

說(shuō)明:對(duì)于大型數(shù)據(jù)結(jié)構(gòu),傳遞指針可顯著降低通道操作的復(fù)制開(kāi)銷。需注意并發(fā)訪問(wèn)時(shí)的數(shù)據(jù)競(jìng)爭(zhēng)問(wèn)題。

示例:

type Payload struct {
    // 大數(shù)據(jù)結(jié)構(gòu)
}

payloadChan := make(chan *Payload, 10)

以上就是關(guān)于channel的一些實(shí)踐技巧,合理運(yùn)用能有效提升并發(fā)程序的執(zhí)行效率和代碼可維護(hù)性。開(kāi)發(fā)者應(yīng)根據(jù)具體場(chǎng)景選擇適當(dāng)?shù)哪J?,并注意資源管理與并發(fā)安全問(wèn)題。

總結(jié)

到此這篇關(guān)于Golang中channel用法舉例詳解的文章就介紹到這了,更多相關(guān)Golang中channel用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 用Go語(yǔ)言編寫一個(gè)簡(jiǎn)單的分布式系統(tǒng)

    用Go語(yǔ)言編寫一個(gè)簡(jiǎn)單的分布式系統(tǒng)

    這篇文章主要介紹了用Go語(yǔ)言編寫一個(gè)簡(jiǎn)單的分布式系統(tǒng),文中的代碼示例講解的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴跟著小編一起來(lái)看看吧
    2023-08-08
  • go?mod詳細(xì)使用教程

    go?mod詳細(xì)使用教程

    go mod是go的一個(gè)模塊管理工具,用來(lái)代替?zhèn)鹘y(tǒng)的GOPATH方案,下面這篇文章主要給大家介紹了關(guān)于go?mod詳細(xì)使用的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • golang 中signal包的Notify用法說(shuō)明

    golang 中signal包的Notify用法說(shuō)明

    這篇文章主要介紹了golang 中signal包的Notify用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-03-03
  • Go語(yǔ)言k8s?kubernetes使用leader?election實(shí)現(xiàn)選舉

    Go語(yǔ)言k8s?kubernetes使用leader?election實(shí)現(xiàn)選舉

    這篇文章主要為大家介紹了Go語(yǔ)言?k8s?kubernetes?使用leader?election選舉,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Golang利用channel協(xié)調(diào)協(xié)程的方法詳解

    Golang利用channel協(xié)調(diào)協(xié)程的方法詳解

    go?當(dāng)中的并發(fā)編程是通過(guò)goroutine來(lái)實(shí)現(xiàn)的,利用channel(管道)可以在協(xié)程之間傳遞數(shù)據(jù),所以本文就來(lái)講講Golang如何利用channel協(xié)調(diào)協(xié)程吧
    2023-05-05
  • 適合PHP同學(xué)的GoFrame框架使用體驗(yàn)及學(xué)習(xí)建議

    適合PHP同學(xué)的GoFrame框架使用體驗(yàn)及學(xué)習(xí)建議

    這篇文章主要為大家介紹了非常適合PHP同學(xué)使用的GoFrame框架設(shè)計(jì)思想使用體驗(yàn)及學(xué)習(xí)建議介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • golang中按照結(jié)構(gòu)體的某個(gè)字段排序?qū)嵗a

    golang中按照結(jié)構(gòu)體的某個(gè)字段排序?qū)嵗a

    在任何編程語(yǔ)言中,關(guān)乎到數(shù)據(jù)的排序都會(huì)有對(duì)應(yīng)的策略,下面這篇文章主要給大家介紹了關(guān)于golang中按照結(jié)構(gòu)體的某個(gè)字段排序的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • go?test?命令示例詳解

    go?test?命令示例詳解

    go?test是Go用來(lái)執(zhí)行測(cè)試函數(shù)(test?function)、基準(zhǔn)函數(shù)(benchmark?function)和示例函數(shù)(example?function)的命令,這篇文章主要介紹了go?test?命令,需要的朋友可以參考下
    2023-11-11
  • golang替換無(wú)法顯示的特殊字符(\u0000,?\000,?^@)

    golang替換無(wú)法顯示的特殊字符(\u0000,?\000,?^@)

    這篇文章主要介紹了golang替換無(wú)法顯示的特殊字符,包括的字符有\(zhòng)u0000,?\000,?^@等,下文詳細(xì)資料,需要的小伙伴可以參考一下
    2022-04-04
  • Golang設(shè)計(jì)模式中的橋接模式詳細(xì)講解

    Golang設(shè)計(jì)模式中的橋接模式詳細(xì)講解

    橋接模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,通過(guò)橋接模式可以將抽象部分和它的實(shí)現(xiàn)部分分離,本文主要介紹了GoLang橋接模式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2023-01-01

最新評(píng)論