C語言中文網 目錄
首頁 > Go語言教程 > Go語言并發 閱讀:2,326

Go語言關閉通道后繼續使用通道

通道是一個引用對象,和 map 類似。map 在沒有任何外部引用時,Go 程序在運行時(runtime)會自動對內存進行垃圾回收(Garbage Collection, GC)。類似的,通道也可以被垃圾回收,但是通道也可以被主動關閉。

格式

使用 close() 來關閉一個通道:

close(ch)

關閉的通道依然可以被訪問,訪問被關閉的通道將會發生一些問題。

給被關閉通道發送數據將會觸發panic

被關閉的通道不會被置為 nil。如果嘗試對已經關閉的通道進行發送,將會觸發宕機,代碼如下:
package main

import "fmt"

func main() {
    // 創建一個整型的通道
    ch := make(chan int)

    // 關閉通道
    close(ch)

    // 打印通道的指針, 容量和長度
    fmt.Printf("ptr:%p cap:%d len:%d\n", ch, cap(ch), len(ch))

    // 給關閉的通道發送數據
    ch <- 1
}
代碼運行后觸發宕機:

panic: send on closed channel

代碼說明如下:
  • 第 7 行,創建一個整型通道。
  • 第 10 行,關閉通道,注意 ch 不會被 close 設置為 nil,依然可以被訪問。
  • 第 13 行,打印已經關閉通道的指針、容量和長度。
  • 第 16 行,嘗試給已經關閉的通道發送數據。

提示觸發宕機的原因是給一個已經關閉的通道發送數據。

從已關閉的通道接收數據時將不會發生阻塞

從已經關閉的通道接收數據或者正在接收數據時,將會接收到通道類型的零值,然后停止阻塞并返回。

操作關閉后的通道:
package main

import "fmt"

func main() {
    // 創建一個整型帶兩個緩沖的通道
    ch := make(chan int, 2)
   
    // 給通道放入兩個數據
    ch <- 0
    ch <- 1
   
    // 關閉緩沖
    close(ch)

    // 遍歷緩沖所有數據, 且多遍歷1個
    for i := 0; i < cap(ch)+1; i++ {
   
        // 從通道中取出數據
        v, ok := <-ch
       
        // 打印取出數據的狀態
        fmt.Println(v, ok)
    }
}
代碼運行結果如下:
0 true
1 true
0 false

代碼說明如下:
  • 第 7 行,創建一個能保存兩個元素的帶緩沖的通道,類型為整型。
  • 第 10 行和第11行,給這個帶緩沖的通道放入兩個數據。這時,通道裝滿了。
  • 第 14 行,關閉通道。此時,帶緩沖通道的數據不會被釋放,通道也沒有消失。
  • 第 17 行,cap() 函數可以獲取一個對象的容量,這里獲取的是帶緩沖通道的容量,也就是這個通道在 make 時的大小。雖然此時這個通道的元素個數和容量都是相同的,但是 cap 取出的并不是元素個數。這里多遍歷一個元素,故意造成這個通道的超界訪問。
  • 第 20 行,從已關閉的通道中獲取數據,取出的數據放在 v 變量中,類型為 int。ok 變量的結果表示數據是否獲取成功。
  • 第 23 行,將 v 和 ok 變量打印出來。

運行結果前兩行正確輸出帶緩沖通道的數據,表明緩沖通道在關閉后依然可以訪問內部的數據。

運行結果第三行的“0 false”表示通道在關閉狀態下取出的值。0 表示這個通道的默認值,false 表示沒有獲取成功,因為此時通道已經空了。我們發現,在通道關閉后,即便通道沒有數據,在獲取時也不會發生阻塞,但此時取出數據會失敗。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo