簡單易懂,解析Go語言中的Channel管道

Channel 管道

1 初始化

可用var聲明nil管道;用make初始化管道;

len(): 緩沖區中元素個數, cap(): 緩沖區大小

//變量聲明 
var a chan int
//使用make初始化
b := make(chan int)  //不帶緩沖區
c := make(chan string,2) // 帶緩沖區
ch1 := make(chan int) // 0 0
ch2 := make(chan int, 2)// 1 2
ch2 <- 1
fmt.Println(len(ch1), len(ch2), cap(ch1), cap(ch2))

2 讀寫操作

用 " <- "來表示數據流向,緩沖區滿時寫/緩沖區空時讀 都會阻塞,直到被其他攜程喚醒

a := make(chan int, 3)
a <- 1 //數據寫入管道
<-a    //管道讀出數據

管道默認雙向可讀寫,但也可在創建函數時顯示單向讀寫

func write(ch chan<- int,a int)  {ch <- a// <- ch  無效運算: <- ch (從僅發送類型 chan<- int 接收)
}func read(ch <-chan int)  {<- ch//ch <- 1  無效運算: ch <- 1 (發送到僅接收類型 <-chan int)
}

讀寫值為nil的管道,會永久阻塞,觸發死鎖

	var ch chan intch <- 1  // fatal error: all goroutines are asleep - deadlock!<-ch  	 // fatal error: all goroutines are asleep - deadlock!

讀寫已關閉管道:有緩沖區成功可讀緩沖區內容,無緩沖區讀零值并返回false;寫已關閉管道會觸發panic

關閉后,等待隊列中的攜程全部喚醒,按照上述規則直接返回

ch1 := make(chan int)
ch2 := make(chan int, 2)
go func() {ch1 <- 1
}()
ch2 <- 2
close(ch1)
close(ch2)
v1, b1 := <-ch1  //0 false
v2, b2 := <-ch2  //2 true
println(v1, v2, b1, b2)
ch1 <- 1  //panic: send on closed channel
ch2 <- 1  //panic: send on closed channel

3 實現原理

簡單來說,channel底層是通過環形隊列來實現其緩沖區的功能。再加上兩個等待隊列來存除被堵塞的攜程。最后加上互斥鎖,保證其并發安全

type hchan struct {
qcount   uint           // 隊列中數據的總數
dataqsiz uint           // 環形隊列的大小
buf      unsafe.Pointer // 指向底層的環形隊列
elemsize uint16         // 元素的大小(以字節為單位)
closed   uint32         // 表示通道是否已關閉
elemtype *_type         // 元素的類型(指向類型信息的指針)
sendx    uint           // 寫入元素的位置
recvx    uint           // 讀取元素的位置
recvq    waitq          // 等待接收的隊列(包含等待接收的 goroutine)
sendq    waitq          // 等待發送的隊列(包含等待發送的 goroutine)// lock 保護 hchan 中的所有字段,以及阻塞在這個通道上的 sudogs 中的幾個字段。
// 在持有此鎖時,不要更改另一個 G 的狀態(特別是不要使 G 變為可運行狀態),
// 因為這可能會與棧收縮操作發生死鎖。
lock mutex //互斥鎖
}

環形隊列是依靠數組實現的(buf指向該數組),實現方法類似雙指針:一個指向寫入位置(sendx),一個指向讀取位置(recvx)
在這里插入圖片描述

等待隊列遵循先進先出,阻塞中的攜程會被相反的操作依次喚醒

如果寫入時,等待接收隊列非空(recvq),那么直接將數據給到等待的攜程,不用經過緩沖區

select可以監控單/多個管道內是否有數據,有就將其讀出;沒有也不會阻塞,直接返回;

select執行順序是隨機的

func main() {ch1 := make(chan int)ch2 := make(chan int)go write(ch1)go write(ch2)for {select {case e := <-ch1:fmt.Printf("ch1:%d\n", e)case e := <-ch2:fmt.Printf("ch2:%d\n", e)default:fmt.Println("none")time.Sleep(1 * time.Second)}}
}
func write(ch chan<- int) {for {ch <- 1time.Sleep(time.Second)}
}

for-range 讀取管道時,管道關閉之后不會繼續讀取管道內數據;

for 循環讀取管道時,管道關閉后,仍會繼續讀取管道內的數據,返回一堆 零值,false

func main() {ch1 := make(chan int)go write(ch1)//for e := range ch1 { // 關閉后不會再從管道讀取數據//	fmt.Print(e)//}//1111for { // 關閉后仍在從管道讀取數據。返回 零值,falsefmt.Print(<-ch1)}//11110000000000000000000000000000000000000.....
}
func write(ch chan<- int) {for i := 1; i < 5; i++ {ch <- 1time.Sleep(time.Second)}close(ch)
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70220.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70220.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70220.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python-leetcode 36.二叉樹的最大深度

題目&#xff1a; 給定一個二叉樹root,返回其最大深度 二叉樹的最大深度是指從根節點到最遠葉子節點的最長路徑上的節點數 方法一&#xff1a;深度優先搜索 知道了左子樹和右子樹的最大深度l和r&#xff0c;那么該二叉樹的最大深度即為:max(l,r)1 而左子樹和右子樹的最大深…

RESTful 的特點與普通 Web API 的區別

RESTful 是一種設計風格&#xff0c;而不僅僅是普通的 Web API。它遵循一些特定的原則和約束&#xff0c;使得 API 更加簡潔、可擴展和易于理解。以下是 RESTful 的特點&#xff0c;以及與普通 Web API 的區別&#xff1a; RESTful 的特點 1. 資源導向 RESTful API 的核心是資…

結構風荷載理論與Matlab計算

結構風荷載理論與matlab計算的實例程序&#xff0c;適合初學者理解matlab風荷載計算 資源文件列表 程序_結構風荷載理論與Matlab計算/chapter1/exam_simWind_1_1.m , 1035 程序_結構風荷載理論與Matlab計算/chapter1/Extrmv.m , 303 程序_結構風荷載理論與Matlab計算/chapter1…

numpy(02 數據類型和數據類型轉換)

numpy(01 入門) 目錄 一、Python NumPy 數據類型 1.1 NumPy 基本類型 1.2 數據類型對象 (dtype) 1.3 具體實例 二、Numpy數據類型轉換 2.1 浮點數據轉換 2.2 整型數據轉換 2.3 浮點數轉整數 一、Python NumPy 數據類型 1.1 NumPy 基本類型 下表列舉了常用 NumPy 基…

【雅思博客04】Silence please!

A: Those people in front of us are making so much noise. It’s so inconsiderate! B: Don’t worry about it; it’s not such a big deal. A: Oh... I can’t hear a thing! Excuse me, can you keep it down? C: Sure, sorry about that! A: Someone’s phone is ri…

【大語言模型_3】ollama本地加載deepseek模型后回答混亂問題解決

背景&#xff1a; 本地下載了DeepSeek-R1-Distill-Qwen-7B模型后&#xff0c;通過ollama create DeepSeek-R1-Distill-Qwen-7B -f ds7b.mf加載模型啟動后回答混亂&#xff0c;無法使用。 解決方法 重新下載模型&#xff0c;選擇了DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf 重…

nginx ngx_http_module(9) 指令詳解

nginx ngx_http_module(9) 指令詳解 nginx 模塊目錄 nginx 全指令目錄 一、目錄 1.1 模塊簡介 ngx_http_uwsgi_module&#xff1a;uWSGI支持模塊&#xff0c;允許Nginx與uWSGI服務器進行通信。uWSGI是一種應用服務器協議&#xff0c;廣泛用于Python Web應用的部署。通過該…

用PyInstaller構建動態腳本執行器:嵌入式Python解釋器與模塊打包 - 簡明教程

技術場景&#xff1a; 需分發的Python工具要求終端用戶可動態修改執行邏輯將Python環境與指定庫&#xff08;如NumPy/Pandas&#xff09;嵌入可執行文件實現"一次打包&#xff0c;動態擴展"的輕量化解決方案。 ▌ 架構設計原理 1. 雙模運行時識別 # 核心判斷邏輯…

山石網科×阿里云通義靈碼,開啟研發“AI智造”新時代

近日&#xff0c;山石網科正式宣布全面接入阿里云通義靈碼企業專屬版&#xff0c;這標志著山石網科在研發智能化、自動化領域邁出重要一步&#xff0c;為研發工作注入強大的AI動力&#xff0c;實現多維度的效率飛躍。 此次合作&#xff0c;阿里云通義靈碼依托強大的AI能力&…

《被討厭的勇氣》(六)

1.自由就是被別人討厭。 2.毫不在意別人的評價、不害怕被別人討厭、不追求被他人認可&#xff0c;如果不付出以上這些代價&#xff0c;那就無法貫徹自己的生活方式&#xff0c;也就是不能獲得自由。 3.在意你的臉的只有你自己。 4.不去干涉別人的課題也不讓別人干涉自己的課題.…

使用 PyTorch 實現標準卷積神經網絡(CNN)

卷積神經網絡&#xff08;CNN&#xff09;是深度學習中的重要組成部分&#xff0c;廣泛應用于圖像處理、語音識別、視頻分析等任務。在這篇博客中&#xff0c;我們將使用 PyTorch 實現一個標準的卷積神經網絡&#xff08;CNN&#xff09;&#xff0c;并介紹各個部分的作用。 什…

SpringBoot2.0整合Redis(Lettuce版本)

前言&#xff1a; 目前java操作redis的客戶端有jedis跟Lettuce。在springboot1.x系列中&#xff0c;其中使用的是jedis, 但是到了springboot2.x其中使用的是Lettuce。 因為我們的版本是springboot2.x系列&#xff0c;所以今天使用的是Lettuce。關于jedis跟lettuce的區別&#…

qt + opengl 給立方體增加陰影

在前幾篇文章里面學會了通過opengl實現一個立方體&#xff0c;那么這篇我們來學習光照。 風氏光照模型的主要結構由3個分量組成&#xff1a;環境(Ambient)、漫反射(Diffuse)和鏡面(Specular)光照。下面這張圖展示了這些光照分量看起來的樣子&#xff1a; 1 環境光照(Ambient …

大模型工具大比拼:SGLang、Ollama、VLLM、LLaMA.cpp 如何選擇?

簡介&#xff1a;在人工智能飛速發展的今天&#xff0c;大模型已經成為推動技術革新的核心力量。無論是智能客服、內容創作&#xff0c;還是科研輔助、代碼生成&#xff0c;大模型的身影無處不在。然而&#xff0c;面對市場上琳瑯滿目的工具&#xff0c;如何挑選最適合自己的那…

stream流常用方法

1.reduce 在Java中&#xff0c;可以使用Stream API的reduce方法來計算一個整數列表的乘積。reduce方法是一種累積操作&#xff0c;它可以將流中的元素組合起來&#xff0c;返回單個結果。對于計算乘積&#xff0c;你需要提供一個初始值&#xff08;通常是1&#xff0c;因為乘法…

pgAdmin4在mac m1上面簡單使用(Docker)

問題 想要在本地簡單了解一下pgAdmin4一些簡單功能。故需要在本機先安裝看一看。 安裝步驟 拉取docker鏡像 docker pull dpage/pgadmin4直接簡單運行pgAdmin4 docker run --name pgAdmin4 -p 5050:80 \-e "PGADMIN_DEFAULT_EMAILuserdomain.com" \-e "PGAD…

ubuntu下安裝TFTP服務器

在 Ubuntu 系統下安裝和配置 TFTP&#xff08;Trivial File Transfer Protocol&#xff09;服務器可以按照以下步驟進行&#xff1a; 1. 安裝 TFTP 服務器軟件包 TFTP 服務器通常使用 tftpd-hpa 軟件包&#xff0c;你可以使用以下命令進行安裝&#xff1a; sudo apt update …

Softing線上研討會 | 自研還是購買——用于自動化產品的工業以太網

| 線上研討會時間&#xff1a;2025年1月27日 16:00~16:30 / 23:00~23:30 基于以太網的通信在工業自動化網絡中的重要性日益增加。設備制造商正面臨著一大挑戰——如何快速、有效且經濟地將工業以太網協議集成到其產品中。其中的關鍵問題包括&#xff1a;是否只需集成單一的工…

vscode創建java web項目

一.項目部署 1.shiftctrlp&#xff0c;選擇java項目 2.選擇maven create from arcetype 3.選擇webapp 4.目錄結構如下&#xff0c;其中index.jsp是首頁 5.找到左下角的servers,添加tomcat服務器 選擇 再選擇&#xff1a; 找到你下載的tomcat 的bin目錄的上一級目錄&#x…

C語言指針學習筆記

1. 指針的定義 指針&#xff08;Pointer&#xff09;是存儲變量地址的變量。在C語言中&#xff0c;指針是一種非常重要的數據類型&#xff0c;通過指針可以直接訪問和操作內存。 2. 指針的聲明與初始化 2.1 指針聲明 指針變量的聲明格式為&#xff1a;數據類型 *指針變量名…