【golang】通道(channel)的基本原理(一)

通道類型的值本身就是并發安全的,這也是Go語言自帶的、唯一一個可以滿足并發安全性的類型。

聲明一個通道類型變量的時候,我們首先要確定該通道類型的元素類型,決定了我們可以通過這個通道傳遞什么類型的數據。

在初始化通道的時候,make函數除了必須接收這樣的類型字面量作為參數,還可以接收一個int類型的參數。

后者是可選的,用于表示該通道的容量。通道的容量,就是指通道最多可以緩存多少個元素值。由此,雖然這個參數是int類型的,但是它是不能小于0的。

當容量為0時,我們可以稱通道為非緩沖通道,也就是不帶緩沖的通道。當容量大于0時,我們可以稱為緩沖通道,也就是帶有緩沖的通道。非緩沖通道和緩沖通道有著不同的數據傳遞方式。

一個通道相當于一個先進先出(FIFO)的隊列。也就是說,通道中的各個元素值都是嚴格地按照發送的順序排列的,先被發送通道的元素值一定會先被接收。元素值的發送和接收都需要用到操作符<-。我們也可以叫它接送操作符。一個左尖括號緊接著一個減號形象地代表了元素值的傳輸方向。

package mainimport "fmt"func main() {ch1 := make(chan int, 3)ch1 <- 2ch1 <- 1ch1 <- 3elem1 := <-ch1fmt.Printf("The first element received from channel ch1: %v\n",elem1)
}

上面代碼中,聲明并初始化了一個元素類型為int、容量為3的通道ch1,并用了三條語句,向該通道先后發送了三個元素值2、1和3.

這里的語句需要這樣寫:依次敲入通道變量的名稱(比如ch1)、接送操作符<-以及想要發送的元素值(比如2),并且這三者之間最好用空格進行分割。

這顯然表達了“這個元素值將被發送該通道”這個語義。由于該通道的容量為 3,所以,我可以在通道不包含任何元素值的時候,連續地向該通道發送三個值,此時這三個值都會被緩存在通道之中。

當我們需要從通道接收元素值的時候,同樣要用接送操作符<-,只不過,這時需要把它寫=在變量名的左邊,用于表達“要從該通道接收一個元素值”的語義。

如果我們需要把如此得來的元素值存起來,那么在接收表達式的左邊就需要依次添加賦值符號(=或:=)和用于存值的變量的名字。因此,語句elem1 := <-ch1會將最先進入ch1的元素2接收來并存入變量elem1。

對通道的發送和接收操作都有哪些基本的特性?

1.對于同一個通道,發送操作之間是互斥的,接收操作之間也是互斥的。

2.發送操作和接收操作中對元素值的處理都是不可分割的。

3.發送操作在完全完成之前會被阻塞。接受操作也是如此。

問題詳解

1.對于同一個通道,發送操作之間是互斥等待,接收操作之間也是互斥的。

在同一時刻,Go語言的運行時系統(以下簡稱運行時系統)只會執行對同一個通道的任意個發送操作中的某一個。

直到這個元素值完全被移出該通道之后,其他針對該通道的接收操作才可能被執行。即使這些操作是并發執行的也是如此。

另外,對于通道的同一個元素值來說,發送操作和接收操作之間也是互斥的。例如,雖然會出現,正在被復制進通道但未復制完成的元素值,但是這時它絕不會被想接收它的一方看到和取走。

需要注意的細節是,元素值從外界進入通道時會被復制。更具體地說,進入通道的并不是在接收操作符右邊的那個元素值,而是它的副本。

另一方面,元素值從通道進入外界時會被移動。這個移動操作實際上包含了兩步,第一步是生成正在通道中的這個元素值的副本,并準備給到接收方,第二步是刪除在通道中的這個元素值。

2.發送操作和接收操作中對元素值的處理都是不可分割的。

這里的"不可分割"的意思是,它們處理元素值時都是一氣呵成的,絕不會被打斷。

例如,發送操作要么還沒復制元素值,要么已經復制完畢,絕不會出現只復制了一部分的情況。

又例如,接收操作在準備好元素值的副本之后,一定會刪除掉通道中的原值,絕不會出現通道中仍有殘留的情況。

這既是為了保證通道中元素值的完整性,也是為了保證通道操作的唯一性。對于通道中的同一個元素值來說,它只可能是某一個發送操作放入的,同時也只可能被某一個接收操作取出。

3.發送操作在完全完成之前會被堵塞。接收操作也是如此

發送操作包括了"復制元素值"和"放置副本到通道內部"這兩個步驟

在這兩個步驟完全完成之前,發起這個發送操作的那句代碼會一直堵塞在那里。也就是說,在它之后的代碼不會有執行的機會,直到這句代碼的阻塞解除。

更細致地說,在通道完成發送操作之后,運行時系統會通知這句代碼所在的goroutine,以使它去爭取繼續運行代碼的機會。

接收操作通常包含了"復制通道內的元素值""放置副本到接收方""刪除原值"三個步驟

在所有這些步驟完全完成之前,發起該操作的代碼也會一直阻塞,直到該代碼所在的goroutine收到了運行時系統的通知并重新獲得運行機會為止。

如此阻塞代碼其實就是為了實現操作的互斥和元素值的完整。

發送操作和接收操作在什么時候可能被長時間的阻塞?

緩沖通道

針對緩沖通道的情況。如果通道已滿,那么對它的所有發送操作都會被阻塞,直到通道中有元素值被接收走。

這時,通道會優先通知最早因此而等待的、那個發送操作所在的goroutine,后者會再次執行發送操作。

由于發送操作在這種情況下被阻塞后,它們所在的goroutine會順序地進入通道內部的發送等待隊列,所以通知的順序總是公平的。

相對的,如果通道已空,那么對它的所有接收操作都會被阻塞,直到通道中有新的元素值出現。這時,通道會通知最早等待的那個接收操作所在的goroutine,并使它再次執行接收操作。

因此而等待的、所有接收操作所在的goroutine,都會按照先后順序被放入通道內部的接收等待隊列。

非緩沖通道

對應非緩沖通道,情況要簡單一點。無論是發送操作還是接收操作,一開始執行就會被阻塞,直到配對的操作也開始執行,才會繼續傳遞。由此可見,非緩沖通道是在用同步的方式傳遞數據。也就是說,只有收發雙方對接上了,數據才會被傳遞。

并且,數據是直接從發送方復制到接收方的,中間并不會用非緩沖通道做中轉。相比之下,緩沖通道則在用異步的方式傳遞數據。

在大多數情況下,緩沖通道會作為收發雙方的中間件。正如前文所述,元素值會先從發送方復制到緩沖通道,之后再由緩沖通道復制給接收方。

但是,當發送操作在執行的時候發現空的通道中,正好有等待的接收操作,那么它會直接把元素值復制給接收方。

注意

對于值為nil的通道,不論它的具體類型是什么,對它的發送操作和接收操作都會永久地處于阻塞狀態。它們所屬的goroutine中的任何代碼,都不再會被執行。

由于通道類型是引用類型,所以它的零值就是nil。換句話說,當我們只聲明該類型的變量但沒有用make函數對它進行初始化時,該變量的值就會是nil所以一定不要忘記初始化通道!

發送操作和接收操作在什么時候會引發panic?

對于一個已初始化,但未來關閉的通道來說,收發操作一定不會引發panic。但是通道一旦關閉,再對它進行發送操作,就會引發panic

當我們把接收表達式的結果同時賦給兩個變量時,第二個變量的類型就是一定bool類型。它的值如果為false就說明通道已經關閉,并且再沒有元素值可取了。
注意,如果通道關閉時,里面還有元素值未被取出,那么接收表達式的第一個結果,仍會是通道中的某一個元素值,而第二個結果值一定會是true。

因此,通過接收表達式的第二個結果值,來判斷通道是否關閉是可能有延時的。

文章學習自郝林老師的《Go語言36講》

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

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

相關文章

一鍵批量修改文件夾名稱,中文瞬間變日語,輕松搞定重命名

大家好&#xff01;現在為了更好地適應全球化發展&#xff0c;許多人都有了海外交流、旅行、學習的需求。但是難免遇到一個問題&#xff1a;在電腦中的中文文件夾名稱如何快速翻譯成日語&#xff1f; 首先&#xff0c;第一步&#xff0c;我們需要打開文件批量改名&#xff0c;…

【Unity】編輯器下查找制定文件下的所有特定資源

需求上很簡單&#xff0c;就是在編輯器下&#xff0c;找到某個制定文件下的所有特定資源&#xff08;UnityEngine.Object&#xff09;。Unity 沒有提供專門的 API&#xff0c;我一開始想在網上搜索代碼&#xff0c;發現沒有現成可以直接用的。 功能實現本身并不復雜&#xff0c…

AWS EKS 集群自動擴容 Cluster Autoscaler

文章目錄 一&#xff0c;需求工作需求說明 二&#xff0c;部署精簡命令執行1&#xff0c;要求2&#xff0c;查看EC2 Auto Scaling groups Tag3&#xff0c;創建Serviceaccount需要的Policy&#xff0c;Role4&#xff0c;部署Cluster Autoscaler5&#xff0c;驗證6&#xff0c;常…

zotero在不同系統的安裝(win/linux)

1 window系統安裝 zotero 官網&#xff1a; https://www.zotero.org/ 官方文檔 &#xff1a;https://www.zotero.org/support/ (官方)推薦常用的插件: https://www.zotero.org/support/plugins 入門視頻推薦&#xff1a; Zotero 文獻管理與知識整理最佳實踐 點擊 exe文件自…

【環境配置】Windows 10 安裝 PyTorch 開發環境,以及驗證 YOLOv8

Windows 10 安裝 PyTorch 開發環境&#xff0c;以及驗證 YOLOv8 最近搞了一臺Windows機器&#xff0c;準備在上面安裝深度學習的開發環境&#xff0c;并搭建部署YOLOv8做訓練和測試使用&#xff1b; 環境&#xff1a; OS&#xff1a; Windows 10 顯卡&#xff1a; RTX 3090 安…

Bug日記-webstorm運行yarn 命令報錯

在windows中輸入yarn -v正確輸出&#xff0c;在webstrom終端中運行yarn命令輸出錯誤 問題&#xff1a;可能是由于 WebStorm 配置問題導致的。 解決方案&#xff1a; 檢查 WebStorm 的終端配置&#xff1a;在 WebStorm 中&#xff0c;點擊菜單欄的 “File”&#xff08;文件&am…

DeepSort:基于檢測的目標跟蹤的經典

本文來自公眾號“AI大道理” DeepSORT在SORT的基礎上引入了深度學習的特征表示和更強大的目標關聯方式&#xff0c;有效地減少了身份切換的數量&#xff0c;緩解了重識別問題。 ? 1、DeepSORT簡介 DeepSORT的主要思想是將目標檢測和目標跟蹤兩個任務相結合。 首先使用目標檢…

排序算法分析——什么時候 用 什么排序

排序算法 & 分析 排序算法歷史排序算法分析很快的排序較快的排序中等的排序很慢的排序 分析的結果0.沒有要求1.對速度有要求2.邊排序邊操作3.條件1&條件24.在有序數中操作5.條件1&條件4 了解各種排序&#xff0c;詳見排序專欄 排序算法歷史 縱觀排序算法的歷史&a…

硬件產品經理:從入門到精通(新書發布)

目錄 簡介 新書 框架內容 相關課程 簡介 在完成多款硬件產品從設計到推向市場的過程后。 筆者于2020年開始在產品領域平臺輸出硬件相關的內容。 在這個過程中經常會收到很多讀者的留言&#xff0c;希望能推薦一些硬件相關的書籍或資料。 其實&#xff0c;筆者剛開始做硬…

10. 實現業務功能--退出登錄

目錄 1. 實現 Controller 2. 單體測試 3. 實現前端界面 退出的具體實現邏輯如下&#xff1a; 1. 用戶訪問退出接口 2. 服務器注銷 Session( 在 Controller 中可以直接進行處理 &#xff09; 3. 返回成功或失敗 4. 如果返回成功瀏覽器跳轉到相應頁面 5. 結束 一般來說&#…

使用VS2015打開.pro文件后,編譯報錯

編譯報錯內容&#xff1a; MSB8036 找不到 Windows SDK 版本10.0.18362.0。請安裝所需的版本的 Windows SDK 或者在項目屬性頁中或通過右鍵單擊解決方案并選擇“重定解決方案目標”來更改 SD 方法&#xff1a; 1.右鍵點擊 Solution上&#xff0c;在彈出的框中點擊“Retarget…

調整數組使奇數全部都位于偶數前面

題目內容&#xff1a; 輸入一個整數數組&#xff0c;實現一個函數&#xff0c; 來調整該數組中數字的順序使得數組中所有的奇數位于數組的前半部分&#xff0c; 所有偶數位于數組的后半部分。 題目思路&#xff1a; 將奇數部分放在前半部分&#xff0c;偶數部分放在后半部分&am…

學習筆記230804---restful風格的接口,delete的傳參方式問題

如果后端提供的刪除接口是restful風格&#xff0c;那么使用地址欄拼接的方式發送請求&#xff0c;數據放在主體中&#xff0c;后端接受不到&#xff0c;當然也還有一種可能&#xff0c;后端在這個接口的接參設置上是req.query接參。 問題描述 今天遇到的問題是&#xff0c;de…

新榜 | CityWalk本地生活商業價值洞察報告

如果說現在有人問&#xff0c;最新的網絡熱詞是什么? “CityWalk”&#xff0c;這可能是大多數人的答案。 近段時間&#xff0c;“CityWalk”刷屏了各種社交媒體&#xff0c;給網友們帶來了一場“城市漫步”之旅。 脫離群體狂歡&#xff0c;這個在社交媒體引發熱議的詞匯背后又…

首發 | FOSS分布式全閃對象存儲系統白皮書

一、 產品概述 1. 當前存儲的挑戰 隨著云計算、物聯網、5G、大數據、人工智能等新技術的飛速發展&#xff0c;數據呈現爆發式增長&#xff0c;預計到2025年中國數據量將增長到48.6ZB&#xff0c;超過80%為非結構化數據。 同時&#xff0c;數字經濟正在成為我國經濟發展的新…

RabbitMQ安裝配置,筆記整理 RabbitMQ3.12.2版本安裝配置

官網下載 RabbitMQ 官方地址&#xff1a;RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQ 下載時需注意Erlang Versions的版本 這里下載的是3.12.2 2.安裝依賴環境 在線安裝依賴環境&#xff1a; yum install build-essential openssl openssl-dev…

銳捷無線產品運維(Web登錄、 命令行登錄)

目錄 登錄AP產品 Console登錄&#xff08;只可以現場登錄&#xff09; Web/Telnet/SSH登錄&#xff08;可以現場、遠程登錄&#xff09; 配置AP的管理地址 通過Web界面遠程登錄 通過Telnet、SSH等命令行的方式登錄 登錄AC產品 Console登錄&#xff08;只可以現場登錄&a…

[bug] 記錄version `GLIBCXX_3.4.29‘ not found 解決方法

在使用mediapipe 這個庫的時候&#xff0c;首次使用出現 GLIBCXX_3.4.29’ not found 錯誤&#xff0c; 看起來是安裝mediapipe 的時候自動升級了 matplotlib 這個庫&#xff0c;導致依賴的 libstd.so 版本不滿足了&#xff0c;GLIBCXX_3.4.29 is an object from libstdc.so.…

【c語言】字符函數與字符串函數(上)

大家好呀&#xff0c;今天給大家分享一下字符函數和字符串函數&#xff0c;說起字符函數和字符串函數大家會想到哪些呢&#xff1f;&#xff1f;我想到的只有求字符串長度的strlen,拷貝字符串的strcpy,字符串比較相同的strcmp,今天&#xff0c;我要分享給大家的是我們一些其他的…