最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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ǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn)

    詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn)

    這篇文章主要介紹了詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 解決Goland 提示 Unresolved reference 錯(cuò)誤的問(wèn)題

    解決Goland 提示 Unresolved reference 錯(cuò)誤的問(wèn)題

    這篇文章主要介紹了解決Goland 提示 Unresolved reference 錯(cuò)誤的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go流程控制代碼詳解

    go流程控制代碼詳解

    這篇文章主要介紹了go流程控制,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-05-05
  • golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例

    golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例

    這篇文章主要介紹了golang 對(duì)私有函數(shù)進(jìn)行單元測(cè)試的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • 簡(jiǎn)單易用的Go逗號(hào)comma ok模式使用詳解

    簡(jiǎn)單易用的Go逗號(hào)comma ok模式使用詳解

    這篇文章主要為大家介紹了簡(jiǎn)單易用的Go逗號(hào)comma ok模式使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 基于Go語(yǔ)言實(shí)現(xiàn)一個(gè)目錄樹(shù)打印工具

    基于Go語(yǔ)言實(shí)現(xiàn)一個(gè)目錄樹(shù)打印工具

    在日常開(kāi)發(fā)中,我們經(jīng)常需要可視化項(xiàng)目的目錄結(jié)構(gòu),下面小編將介紹一款用Go語(yǔ)言開(kāi)發(fā)的目錄樹(shù)打印工具,它不僅能生成美觀的目錄結(jié)構(gòu)圖,還提供多種實(shí)用功能
    2025-06-06
  • golang字符編碼的實(shí)現(xiàn)

    golang字符編碼的實(shí)現(xiàn)

    本文主要介紹了golang字符編碼的實(shí)現(xiàn),,有三種編碼形式:UTF-8,UTF-16,UTF-32,下面就來(lái)介紹一下如何使用,感興趣的可以了解一下
    2024-08-08
  • GoLang日志監(jiān)控系統(tǒng)實(shí)現(xiàn)

    GoLang日志監(jiān)控系統(tǒng)實(shí)現(xiàn)

    這篇文章主要介紹了GoLang日志監(jiān)控系統(tǒng)的實(shí)現(xiàn)流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-12-12
  • go循環(huán)依賴的最佳解決方案

    go循環(huán)依賴的最佳解決方案

    ? import cycle not allowed(循環(huán)依賴不被允許)相信作為每一個(gè)golang語(yǔ)言使用研發(fā),都遇到過(guò)這個(gè)令人頭痛的報(bào)錯(cuò),循環(huán)依賴是指兩個(gè)或多個(gè)模塊之間互相依賴,形成了一個(gè)閉環(huán)的情況,本文會(huì)結(jié)合部分案例對(duì)解決方案進(jìn)行講解,需要的朋友可以參考下
    2023-10-10
  • Golang設(shè)計(jì)模式中抽象工廠模式詳細(xì)講解

    Golang設(shè)計(jì)模式中抽象工廠模式詳細(xì)講解

    抽象工廠模式用于生成產(chǎn)品族的工廠,所生成的對(duì)象是有關(guān)聯(lián)的。如果抽象工廠退化成生成的對(duì)象無(wú)關(guān)聯(lián)則成為工廠函數(shù)模式。比如本例子中使用RDB和XML存儲(chǔ)訂單信息,抽象工廠分別能生成相關(guān)的主訂單信息和訂單詳情信息
    2023-01-01

最新評(píng)論

巴彦县| 万载县| 开原市| 望谟县| 沧源| 乐清市| 双鸭山市| 华安县| 乐陵市| 建平县| 景泰县| 金塔县| 遵义市| 淄博市| 临潭县| 当涂县| 洛南县| 兴和县| 兴文县| 洪洞县| 界首市| 唐海县| 庆云县| 渭南市| 通河县| 泉州市| 六枝特区| 咸丰县| 奈曼旗| 周口市| 乌鲁木齐县| 京山县| 新化县| 绵竹市| 白玉县| 澄江县| 平泉县| 朝阳县| 左权县| 昂仁县| 河西区|