Golang協程與通道整理


協程goroutine
 
     不由OS調度,而是用戶層自行釋放CPU,從而在執行體之間切換。Go在底層進行協助實現
     涉及系統調用的地方由Go標准庫協助釋放CPU
     總之,不通過OS進行切換,自行切換,系統運行開支大大降低
 
 
通道channel
 
並發編程的關鍵在於執行體之間的通信,go通過通過channel進行通信
channel可以認為類似其他OS體系中的消息隊列,只不過在go中原生支持,因而易用
 
消息隊列有哪些值得關注的地方?常見問題包括創建、關閉或刪除、阻塞、超時、優先級等,golang中也不例外。羅列如下:
     可否探測隊列是滿或空?或者說是否可以不阻塞地嘗試讀寫?
     讀阻塞和寫阻塞時關閉會怎樣?
     關閉后未讀取的消息會被拋棄?
     往關閉的channel發送數據或讀取數據會怎樣?
     怎樣探測channel的關閉?
     兩個地方讀或寫阻塞同一個channel,有沒有優先級?
     是否可以設定阻塞的超時時間?
     阻塞時怎樣可以被彈出來?比如某些信號?
事實上,知道存在這些問題並進行分門別類是重要的,但知道這些問題的答案卻不緊要,因為一般不會太過古怪,使用時臨時試驗一下即可。
 
已知的部分答案:
     好像不能不阻塞地嘗試讀寫
     關閉會導致退出阻塞(似乎是一個不錯的特性)
     可以探測關閉
     channel本身不能設定超時
了解這些似乎已經足夠。
 
 
與眾不同的地方值得我們重點留意,包括:
     除基本讀寫方式外,還有哪些特別的讀寫方式?在阻塞、關閉、超時方面又有什么不同?發現了select、range兩個關鍵字
     推薦的多通道讀
     推薦的同步方法
     推薦的超時方法
 
 
 
select
 
select可以實現無阻塞的多通道嘗試讀寫,以及阻塞超時
     
var c, c1, c2, c3  chan  int
var i1, i2  int
 
select {
      case i1 = <-c1: //如果能走通任何case則隨機走一個
         print( "received ", i1, " from c1\n" )
      case c2 <- i2:
         print( "sent ", i2, " to c2\n" )
      case i3, ok := (<-c3):
         if ok {
                 print( "received ", i3, " from c3\n" )
        }  else {
                 print( "c3 is closed\n")
        }
      default: // 如果case都阻塞,則走default,如果無default,則阻塞在case
        // default中可以不讀寫任何通道,那么只要default提供不阻塞的出路,就相當於實現了對case的無阻塞嘗試讀寫
         print( "no communication\n")
}
 
實現阻塞超時的方法是,只要不給default出路,而在case中實現一個超時
 
timeout :=  make ( chan  bool, 1)
go  func () {
    time.Sleep(1e9) // 這是等待1秒鍾
    timeout <-  true
}()
 
// 用timeout這個通道作為阻塞超時的出路
select {
   case <-ch:
  // 處理從ch中讀到的數據
   case <-timeout:
  // 如果case都阻塞了,那么1秒鍾后會從這里找到出路
 
 
range
 
range可以在for循環中讀取channel
Go文檔的翻譯文是:對於信道,其迭代值產生為在該信道上發送的連續值,直到該信道被關閉。若該信道為 nil,則range表達式將永遠阻塞
經過試驗,range會阻塞,並且可以通過關閉channel來解除阻塞。
 
package main
 
import (
       "fmt"
)
 
func main() {
      ch :=  makechan  int )
 
        go  func () {
              for i := 0; i < 10; i++ {
                  ch <- i
            }
 
      }()
 
      
        for w :=  range ch {
            fmt.Println( "fmt print" , w)
              if w > 5 {
                   //break // 在這里break循環也可以
                    close(ch)
            }
      }
      fmt.Println( "after range or close ch!" )
}
 
 
Golang的並發編程還有其他細節,但以上是最主要脈絡。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM