Golang 并發機制 CSP模型

Golang 并發機制 CSP模型

1 前言

go語言的最大兩個亮點,一個是 goroutine ,一個就是 chan 了。二者合體的典型應用CSP,基本就是大家認可的并行開發神器,簡化了并行程序的開發難度,我們來看一下CSP。

2 CSP是什么

CSPCommunicating Sequential Process 的簡稱,中文可以叫做 通信順序進程 ,是一種并發編程模型,是一個很強大的并發數據模型,是上個世紀七十年代提出的,用于描述兩個獨立的并發實體通過共享的通訊 channel(管道) 進行通信的并發模型。相對于Actor模型,CSP中channel是第一類對象,它不關注發送消息的實體,而關注與發送消息時使用的channel。

嚴格來說,CSP 是一門形式語言(類似于calculus),用于描述并發系統中的互動模式,也因此成為一眾面向并發的編程語言的理論源頭,并衍生出了 Occam/Limbo/Golang…

而具體到編程語言,如 Golang,其實只用到了 CSP 的很小一部分,即理論中的 Process/Channel(對應到語言中的 goroutine/channel):這兩個并發原語之間沒有從屬關系, Process 可以訂閱任意個 Channel,Channel 也并不關心是哪個 Process 在利用它進行通信;Process 圍繞 Channel 進行讀寫,形成一套有序阻塞和可預測的并發模型。

3 Golang CSP

與主流語言通過共享內存來進行并發控制方式不同,Go 語言采用了 CSP 模式。這是一種用于描述兩個獨立的并發實體通過共享的通訊 Channel(管道)進行通信的并發模型。

Golang 就是借用CSP模型的一些概念為之實現并發進行理論支持,其實從實際上出發,go語言并沒有完全實現了CSP模型的所有理論,僅僅是借用了 process和channel這兩個概念。process是在go語言上的表現就是 goroutine 是實際并發執行的實體,每個實體之間是通過channel通訊來實現數據共享。

Go語言的CSP模型是由協程Goroutine與通道Channel實現:

  • Go協程goroutine: 是一種輕量線程,它不是操作系統的線程,而是將一個操作系統線程分段使用,通過調度器實現協作式調度。是一種綠色線程,微線程,它與Coroutine協程也有區別,能夠在發現堵塞后啟動新的微線程。
  • 通道channel: 類似Unix的Pipe,用于協程之間通訊和同步。協程之間雖然解耦,但是它們和Channel有著耦合。

4 Channel

Goroutine 和 channel 是 Go 語言并發編程的 兩大基石。Goroutine 用于執行并發任務,channel 用于 goroutine 之間的同步、通信。

Channel 在 gouroutine 間架起了一條管道,在管道里傳輸數據,實現 gouroutine 間的通信;由于它是線程安全的,所以用起來非常方便;channel 還提供 “先進先出” 的特性;它還能影響 goroutine 的阻塞和喚醒。

相信大家一定見過一句話:

Do not communicate by sharing memory; instead, share memory by communicating.
不要通過共享內存來通信,而要通過通信來實現內存共享。

這就是 Go 的并發哲學,它依賴 CSP 模型,基于 channel 實現。

channel 實現 CSP

Channel 是 Go 語言中一個非常重要的類型,是 Go 里的第一對象。通過 channel,Go 實現了通過通信來實現內存共享。Channel 是在多個 goroutine 之間傳遞數據和同步的重要手段。

使用原子函數、讀寫鎖可以保證資源的共享訪問安全,但使用 channel 更優雅。

channel 字面意義是 “通道”,類似于 Linux 中的管道。聲明 channel 的語法如下:


chan T // 聲明一個雙向通道
chan<- T // 聲明一個只能用于發送的通道
<-chan T // 聲明一個只能用于接收的通道COPY

單向通道的聲明,用 <- 來表示,它指明通道的方向。你只要明白,代碼的書寫順序是從左到右就馬上能掌握通道的方向是怎樣的。

因為 channel 是一個引用類型,所以在它被初始化之前,它的值是 nil ,channel 使用 make 函數進行初始化。可以向它傳遞一個 int 值,代表 channel 緩沖區的大小(容量),構造出來的是一個緩沖型的 channel;不傳或傳 0 的,構造的就是一個非緩沖型的 channel。

兩者有一些差別:非緩沖型 channel 無法緩沖元素,對它的操作一定順序是 “ 發送 -> 接收 -> 發送 -> 接收 -> ……”,如果想連續向一個非緩沖 chan 發送 2 個元素,并且沒有接收的話,第一次一定會被阻塞;對于緩沖型 channel 的操作,則要 “寬松” 一些,畢竟是帶了 “緩沖” 光環。

通道(channel)模型

對 chan 的發送和接收操作都會在編譯期間轉換成為底層的發送接收函數。

Channel 分為兩種:帶緩沖、不帶緩沖。對不帶緩沖的 channel 進行的操作實際上可以看作 “同步模式”,帶緩沖的則稱為 “異步模式”。

同步模式下,發送方和接收方要同步就緒,只有在兩者都 ready 的情況下,數據才能在兩者間傳輸(后面會看到,實際上就是內存拷貝)。否則,任意一方先行進行發送或接收操作,都會被掛起,等待另一方的出現才能被喚醒。

異步模式下,在緩沖槽可用的情況下(有剩余容量),發送和接收操作都可以順利進行。否則,操作的一方(如寫入)同樣會被掛起,直到出現相反操作(如接收)才會被喚醒。

  • 同步模式下,必須要使發送方和接收方配對,操作才會成功,否則會被阻塞;
  • 異步模式下,緩沖槽要有剩余容量,操作才會成功,否則也會被阻塞。

簡單來說,CSP 模型由并發執行的實體(線程或者進程或者協程)所組成,實體之間通過發送消息進行通信,
這里發送消息時使用的就是通道,或者叫 channel。

CSP 模型的關鍵是關注 channel,而不關注發送消息的實體。Go 語言實現了 CSP 部分理論,goroutine 對應 CSP 中并發執行的實體,channel 也就對應著 CSP 中的 channel。

5 Goroutine

Goroutine 是實際并發執行的實體,它底層是使用協程(coroutine)實現并發,coroutine是一種運行在用戶態的用戶線程,類似于 greenthread,go底層選擇使用coroutine的出發點是因為,它具有以下特點:

  • 用戶空間 避免了內核態和用戶態的切換導致的成本
  • 可以由語言和框架層進行調度
  • 更小的棧空間允許創建大量的實例

可以看到第二條 用戶空間線程的調度不是由操作系統來完成的,像在java 1.3中使用的greenthread的是由JVM統一調度的(后java已經改為內核線程),還有在ruby中的fiber(半協程) 是需要在重新中自己進行調度的,而goroutine是在golang層面提供了調度器,并且對網絡IO庫進行了封裝,屏蔽了復雜的細節,對外提供統一的語法關鍵字支持,簡化了并發程序編寫的成本。

6 Goroutine 調度器

Go并發調度: GPM模型

在操作系統提供的內核線程之上,Go搭建了一個特有的兩級線程模型。goroutine機制實現了M : N的線程模型,goroutine機制是協程(coroutine)的一種實現,golang內置的調度器,可以讓多核CPU中每個CPU執行一個協程。

7 總結

Golang 的 channel 將 goroutine 隔離開,并發編程的時候可以將注意力放在 channel 上。在一定程度上,這個和消息隊列的解耦功能還是挺像的。如果大家感興趣,還是來看看 channel 的源碼吧,對于更深入地理解 channel 還是挺有用的。

Go 通過 channel 實現 CSP 通信模型,主要用于 goroutine 之間的消息傳遞和事件通知。

有了 channel 和 goroutine 之后,Go 的并發編程變得異常容易和安全,得以讓程序員把注意力留到業務上去,實現開發效率的提升。

參考

  • https://blog.csdn.net/kenkao/article/details/124255627

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

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

相關文章

在Windows 11中運行磁盤清理工具的9種方法,總有一種適合你

自Windows98以來,微軟在操作系統中包含了一個內置的清理工具。當用戶轉向第三方清理應用程序時,這個值得信賴的實用程序站穩了腳跟。微軟甚至宣布,第三方應用程序幾乎毫無用處,刪除注冊表項不是一個好主意。 磁盤清理工具可以幫助刪除臨時文件、舊的更新日志、縮略圖緩存和…

git安裝與使用4.3

一、git的安裝 1、下載git包 下載git包url&#xff1a;https://git-scm.com/download/win 下載包分為&#xff1a;64位和32位 2、點擊安裝包 2、選擇安裝路徑 3、 點擊下一步 4、點擊next 5、點擊next 6、點擊next 7、 8、 9、 10、 11、 12、在桌面空白處&#xff0c;右鍵…

【SpringBoot】測試單元使用多線程

&#x1f4dd;個人主頁&#xff1a;五敷有你 &#x1f525;系列專欄&#xff1a;SpringBoot ??穩重求進&#xff0c;曬太陽 問題產生 今天學習了樂觀鎖&#xff0c;但在測試單元執行多線程的時候出現了問題&#xff0c;多線程并沒有直接結果 在控制臺沒有任何輸出…

KubeSphere平臺安裝系列之二【Linux單節點部署KubeSphere】(2/3)

**《KubeSphere平臺安裝系列》** 【Kubernetes上安裝KubeSphere&#xff08;親測–實操完整版&#xff09;】&#xff08;1/3&#xff09; 【Linux單節點部署KubeSphere】&#xff08;2/3&#xff09; 【Linux多節點部署KubeSphere】&#xff08;3/3&#xff09; **《KubeS…

RocketMQ學習筆記一

課程來源&#xff1a;002-MQ簡介_嗶哩嗶哩_bilibili &#xff08;尚硅谷老雷&#xff0c;時長19h&#xff09; 第1章 RocketMQ概述 1. MQ是什么&#xff1f; 2. MQ用途有哪些&#xff1f; 限流削峰&#xff1b;異步解耦&#xff1b;數據收集。 3. 常見MQ產品有哪些&對比…

Kaggle競賽之Titanic存活預測2

提高代碼規范性&#xff0c;基于上一個 baseline 的提高 import pandas as pd from sklearn.preprocessing import LabelBinarizer from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split#數據劃分方法 from sklearn.ensem…

哪個超聲波清洗機品牌值得入手?銷量榜品牌值得選購!

在科技日益發展的今天&#xff0c;超聲波清洗技術以其高效、便捷和深度清潔的特點&#xff0c;已經深入到生活的諸多領域&#xff0c;從精密儀器到珠寶首飾&#xff0c;從眼鏡框到假牙&#xff0c;甚至是廚房用品的日常護理&#xff0c;都能見到超聲波清洗機的身影。面對市場上…

無人機兩次飛行的圖像數據配準與幾何校正方法研究

標題: 無人機兩次飛行的圖像數據配準與幾何校正方法研究 摘要: 本文研究了利用無人機獲取的兩次飛行的圖像數據進行配準與幾何校正的方法。無人機航拍技術在地理信息獲取和空間數據應用中具有重要意義,但由于飛行條件、攝影設備和環境等因素的影響,同一區域的不同飛行任務…

【基頻提取算法-YIN】

本文對基頻提取算法 YIN 做以介紹。如有表述不當之處歡迎批評指正。歡迎任何形式的轉載&#xff0c;但請務必注明出處。 文章目錄 1. 引言2. YIN 各模塊代碼講解2.1. 差分函數的實現2.2. 累積均值歸一化差分函數的實現2.3. 絕對閾值2.4. 拋物線插值2.5. 最優局部估計 3. 總結 1…

免殺實戰-EDR對抗

文章目錄 殺軟分析BOF.NET 殺軟分析 x64dgb簡單調試發現該edr在r3環對ntdll.dll和kernel32.dll關鍵函數均存在hook&#xff0c;這里硬盤讀取原來的dll進行重新加載&#xff0c;原理如圖 loader // dllmain.cpp : 定義 DLL 應用程序的入口點。 #include "pch.h" #in…

DSI2協議之BTA行為理解

概念: DSI協議spec支持總線控制權在master和slave之間發生交換,即通過bus turn around來實現; BUS TURN AROUND: BTA 的實現是通過controller—>cdphy的turnrequest信號來實現; 關于控制器發出turnrequest給phy,phy通過lvds/trio線輸出turnaround sequence如下圖中…

LeetCode刷題筆記之二叉樹(四)

一、二叉搜索樹的應用 1. 700【二叉搜索樹中的搜索】 題目&#xff1a; 給定二叉搜索樹&#xff08;BST&#xff09;的根節點 root 和一個整數值 val。你需要在 BST 中找到節點值等于 val 的節點。 返回以該節點為根的子樹。 如果節點不存在&#xff0c;則返回 null 。代碼&a…

BUGKU 本地管理員

打開環境&#xff0c;先F12查看看到一串代碼。Base64解碼一下&#xff0c;得到的應該是密碼&#xff0c;然后輸入admin | test123試一下 使用BP抓包&#xff0c;修改XFF&#xff0c;得到flag

將鏡像上傳到私有鏡像倉庫Harbor

首先你需要安裝Harbor服務&#xff1a; https://blog.csdn.net/qq_50247813/article/details/136388229 客戶端已經安裝docker&#xff1a; https://docs.docker.com/engine/install/centos/ 在docker客戶端登錄 Harbor 我的Harbor 服務器地址&#xff1a; 192.168.44.161 賬號…

關于編寫測試用例的一些思考

測試用例是QA同學的基本功&#xff0c;每個人都有一套編寫測試用例的體系&#xff0c;本文是作者結合自身的工作經驗以及閱讀一些測試相關的書籍后的一些看法&#xff0c;歡迎大家一起討論學習。 測試設計 測試用例格式 面試中一些常見的問題 1.APP測試與服務端測試的區別&am…

微服務中的Feign:優雅實現遠程調用的秘密武器(二)

本系列文章簡介&#xff1a; 本系列文章將深入探討Feign的特點、原理以及在微服務中的應用場景&#xff0c;幫助讀者更好地理解和使用這個優秀的遠程調用工具。無論您是初學者還是有經驗的開發人員&#xff0c;本文都將為您揭示Feign的秘密&#xff0c;并帶您一起走進微服務的世…

何愷明新作 l-DAE:解構擴散模型

何愷明新作 l-DAE&#xff1a;解構擴散模型 提出背景擴散模型步驟如何在不影響數據表征能力的同時簡化模型&#xff1f;如何進一步推動模型向經典DAE靠攏&#xff1f;如何去除對生成任務設計的DDM中不適用于自監督學習的部分&#xff1f;如何改進DDM以專注于清晰圖像表示的學習…

2024華為軟件測試筆試面試真題,抓緊收藏不然就看不到了

一、選擇題 1、對計算機軟件和硬件資源進行管理和控制的軟件是&#xff08;D&#xff09; A.文件管理程序 B.輸入輸出管理程序 C.命令出來程序 D.操作系統 2、在沒有需求文檔和產品說明書的情況下只有哪一種測試方法可以進行的&#xff08;A&#xff09; A.錯誤推測法測試…

Docker 快速入門實操教程(完結)

Docker 快速入門實操教程&#xff08;完結&#xff09; Docker&#xff0c;啟動&#xff01; 如果安裝好Docker不知道怎么使用&#xff0c;不理解各個名詞的概念&#xff0c;不太了解各個功能的用途&#xff0c;這篇文章應該會對你有幫助。 前置條件&#xff1a;已經安裝Doc…

【Hadoop】在spark讀取clickhouse中數據

讀取clickhouse數據庫數據 import scala.collection.mutable.ArrayBuffer import java.util.Properties import org.apache.spark.sql.SaveMode import org.apache.spark.sql.SparkSessiondef getCKJdbcProperties(batchSize: String "100000",socketTimeout: Strin…