<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Goroutine間的“靈魂管道”:Channel如何實現數據同步與因果傳遞?

      Channel是連接Goroutine的“管道”,是CSP理念在Golang中的具象化實現。它不僅是數據傳遞的隊列,更是Goroutine間同步的天然工具,讓開發者無需訴諸顯式的鎖或條件變量。

      func main() {
      	ch := make(chan int, 1) // 創建一個int,緩沖區大小為1的Channel
      	ch <- 2                 // 將2發送到ch
      
      	go func() {  // 開啟一個異步Goroutine
      		n, ok := <-ch // n接收從ch發出的值,如果沒有接收到數據,將會阻塞等待
      		if ok {
      			fmt.Println(n) // 2
      		}
      	}()
      
      	close(ch) // 關閉Channel
      }
      

      Channel數據結構
      Channel 在運行時使用src/runtime/chan.go 結構體表示。我們在 Go 語言中創建新的 Channel 時,實際上創建的是如下所示的結構。

      type hchan struct {
      	qcount   uint           // 隊列中所有數據總數
      	dataqsiz uint           // 環形隊列的 size
      	buf      unsafe.Pointer // 指向 dataqsiz 長度的數組
      	elemsize uint16         // 元素大小
      	closed   uint32
      	elemtype *_type         // 元素類型
      	sendx    uint           // 已發送的元素在環形隊列中的位置
      	recvx    uint           // 已接收的元素在環形隊列中的位置
      	recvq    waitq          // 接收者的等待隊列
      	sendq    waitq          // 發送者的等待隊列
      
      	lock mutex
      }
      

      image

      runtime.hchan 結構體中的五個字段 qcount、dataqsiz、buf、sendx、recv 構建底層的循環隊列。除此之外,elemsize 和 elemtype 分別表示當前 Channel 能夠收發的元素類型和大小。
      sendq 和 recvq 存儲了當前 Channel 由于緩沖區空間不足而阻塞的 Goroutine 列表,這些等待隊列使用雙向鏈表 runtime.waitq表示,鏈表中所有的元素都是runtime.sudog 結構。

      type waitq struct {
          first *sudog 
          last  *sudog
      }
      

      runtime.sudog(Scheduling Unit Descriptor)是用于實現Goroutine調度的一種數據結構。它包含了與Goroutine相關的信息,如Goroutine的狀態、等待的條件、等待的時間等。
      當一個Goroutine需要等待某個事件或條件時,它會創建一個runtime.sudog,并將其加入到等待隊列中。當事件或條件滿足時,等
      待隊列中的runtime.sudog會被喚醒,從而允許對應的Goroutine繼續執行。
      Channel發送數據
      1)如果等待接收的隊列recvq中存在Goroutine,那么直接把正在發送的值發送給等待接收的Goroutine。
      image

      2)當緩沖區未滿時,找到sendx所指向的緩沖區數組的位置,將正在發送的值拷貝到該位置,并增加sendx索引以及釋放鎖。

      image

      3)如果是阻塞發送,那么就將當前的Goroutine打包成一個sudog結構體,并加入到Channel的發送隊列sendq里。

      image

      之后則調用goparkunlock將當前Goroutine設置為_Gwaiting狀態并解鎖,進入阻塞狀態等待被喚醒;如果被調度器喚醒,執行清理
      工作并最終釋放對應的sudog結構體。

      Channel接收數據
      1)如果等待發送的隊列sendq里存在掛起的Goroutine,那么有兩種情況:當前Channel無緩沖區,或者當前Channel已滿。從sendq中取出最先阻塞的Goroutine,然后調用recv方法,此時需做如下判斷:

      1. 如果無緩沖區,那么直接從sendq接收數據;
      2. 如果緩沖區已滿,從buf隊列的頭部接收數據,并把數據加到buf隊列的尾部;
      3. 最后調用goready函數將等待發送數據的Goroutine的狀態從_Gwaiting置為_Grunnable,等待下一次調度。
        當緩沖區已滿時的處理過程。

      image

      2)如果緩沖區buf中還有元素,那么就走正常的接收,將從buf中取出的元素拷貝到當前協程的接收數據目標內存地址中。值得注意的是,即使此時Channel已經關閉,仍然可以正常地從緩沖區buf中接收數據。
      3)如果是阻塞模式,且當前沒有數據可以接收,那么就需要將當前Goroutine打包成一個sudog加入到Channel的等待接收隊列recvq中,將當前Goroutine的狀態置為_Gwaiting,等待喚醒。

      image

      Channel與happens-before 關系
      Channel happens-before 規則有 4 條。
      1)對一個元素的send操作happens-before對應的receive 完成操作。

      var c = make(chan int, 10) // buffered或者unbuffered
      var a string
      
      func f() {
         // a 的初始化 happens-before 往ch中發送數據
      	a = "hello, world"
         c <- 0
      }
      
      func main() {
      	go f()
          // 往ch發送數據 happens-before 從ch中讀取出數據
      	<-c
         // 打印a的值 happens-after 第12行
         // 打印a的結果值“hello world”
      	print(a)
      }
      

      2)對Channel的close操作happens-before receive 端的收到關閉通知操作。

      var c = make(chan int, 10) // buffered或者unbuffered
      var a string
      
      func f() {
         // a 的初始化 happens-before close ch
      	a = "hello, world"
         close(c)
      }
      
      func main() {
      	go f()
          // close ch happens-before 從ch中讀取出數據
      	<-c
         // 打印a的值 happens-after 第12行
         // 打印a的結果值“hello world”
      	print(a)
      }
      

      3)對于Unbuffered Channel,對一個元素的receive 操作happens-before對應的send完成操作。

      var c = make(chan int) // unbuffered
      var a string
      
      func f() {
         // a 的初始化 happens-before 從ch中讀取出數據
      	a = "hello, world"
         <-c
      }
      
      func main() {
      	go f()
          // 從ch中讀取出數據 happens-before 往ch發送數據
      	c <- 0   
         // 打印a的值 happens after 第12行
         // 打印a的結果值“hello world”
      	print(a)
      }
      

      4)如果 Channel 的容量是 c(c>0),那么,第 n 個 receive 操作 happens-before 第 n+c 個 send 的完成操作。規則3是規則4 c=0時的特例。

      Channel使用場景
      1)并發控制:通過控制帶緩沖的Channel 的隊列大小來限制并發的數量。

      func worker(id int, sem chan struct{}) {
      	// 獲取許可
      	sem <- struct{}{}
      	time.Sleep(time.Second) // 模擬耗時操作
      	// 釋放許可
      	<-sem
      }
      
      func main() {
      	// 創建一個緩沖區為2的Channel
      	sem := make(chan struct{}, 2)
      
      	for i := 0; i < 5; i++ {
      		go worker(i, sem)
      	}
      }
      

      2)信號通知:使用一個無緩沖的 Channel 來通知一個 Goroutine 任務已經完成。

      func main() {
      	done := make(chan bool)
      
      	go func() {
      		time.Sleep(2 * time.Second) // 模擬耗時操作
      		// 發送信號表示工作已完成
      		done <- true
      	}()
      
      	<-done // 等待信號
      }
      

      3)異步操作結果獲取:在一個 Goroutine 中執行異步操作,然后通過 Channel 將結果發送到另一個 Goroutine。

      func asyncTask() <-chan int {
      	ch := make(chan int)
      	go func() {
      		// 模擬異步操作
      		time.Sleep(2 * time.Second)
      		ch <- 1 // 發送結果
      		close(ch)
      	}()
      	return ch
      }
      
      func main() {
      	ch := asyncTask()
      	time.Sleep(1 * time.Second) // 模擬其他操作
      	result := <-ch // 獲取異步操作的結果
      }
      

      總結:控制與編排,殊途同歸
      Java 與 Golang 在并發模型上的差異,深刻地體現了兩種構建程序確定性的不同哲學:
      1)Java (共享內存):采用顯式同步的路徑。它為開發者提供了強大的底層控制能力(鎖、內存屏障),但要求開發者必須承擔起預見并管理資源競態的心智負擔。確定性來自于對臨界區和內存可見性的嚴格手工控制。
      2)Golang (消息傳遞):采用隱式因果的路徑。它通過 Channel 將數據的所有權在 Goroutine 間傳遞,將并發問題從“共享數據訪問”轉化為“數據流設計”。確定性來自于消息傳遞建立的自然因果順序,從而在結構上規避了競態。
      Java的路徑是“先有并發,后加約束”,而Golang的路徑是“通過約束,實現并發”。兩者并非優劣之分,而是針對不同問題域和開發哲學的選擇。Java的完備工具集賦予了處理極端復雜場景的靈活性,而Golang的簡約設計則為構建清晰、可靠、易于推理的并發系統提供了優雅的范式。
      最終,無論是顯式的同步約束,還是隱式的因果傳遞,它們都通向并發編程的圣杯——在多核時代,構建出可預測、可維護且高性能的軟件系統。這兩種思想的碰撞與融合,正持續推動著現代并發編程的演進。

      很高興與你相遇!如果你喜歡本文內容,記得關注哦

      posted on 2025-10-14 22:13  poemyang  閱讀(119)  評論(2)    收藏  舉報

      導航

      主站蜘蛛池模板: 国产av中文字幕精品| 少妇高潮水多太爽了动态图| 少妇真人直播免费视频| 一道本AV免费不卡播放| 国内自产少妇自拍区免费| 国产女同疯狂作爱系列 | 99热国产这里只有精品9| 修武县| 久久亚洲精品11p| 国产精品多p对白交换绿帽| 性一交一黄一片| 亚洲女女女同性video| 2020年最新国产精品正在播放| 不卡乱辈伦在线看中文字幕| 最新日韩精品中文字幕| 久久热这里这里只有精品| 亚洲熟妇少妇任你躁在线观看无码| 在线a人片免费观看| 久久国产一区二区三区| 日日噜久久人妻一区二区| 欧美肥老太牲交大战| 中文字幕理伦午夜福利片| 午夜成人理论无码电影在线播放| 高清无码18| 国产色视频一区二区三区| 国产精品无码av不卡| 国产精品中文一区二区| 成全我在线观看免费第二季| 精品亚洲国产成人av制服| 四虎国产成人永久精品免费| 亚洲一区二区乱码精品| 久久狠狠一本精品综合网| 国产高清自产拍av在线| 亚洲精品无码日韩国产不卡av| 欧美黑人巨大xxxxx| 日本一本正道综合久久dvd| 亚洲人成网站观看在线观看 | 亚洲国产一区二区三区亚瑟| 久久精品亚洲成在人线av麻豆| 日韩丝袜欧美人妻制服| 99久久精品午夜一区二区|