欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言入門學(xué)習(xí)之Channel通道詳解

 更新時間:2022年07月24日 10:22:20   作者:鹿魚  
go routine可以使用channel來進(jìn)行通信,使用通信的手段來共享內(nèi)存,下面這篇文章主要給大家介紹了關(guān)于Go語言入門學(xué)習(xí)之Channel通道的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

不同于傳統(tǒng)的多線程并發(fā)模型使用共享內(nèi)存來實現(xiàn)線程間通信的方式,go 是通過 channel 進(jìn)行協(xié)程 (goroutine) 之間的通信來實現(xiàn)數(shù)據(jù)共享。

channel,就是一個管道,可以想像成 Go 協(xié)程之間通信的管道。它是一種隊列式的數(shù)據(jù)結(jié)構(gòu),遵循先入先出的規(guī)則。

通道的聲明

每個通道都只能傳遞一種數(shù)據(jù)類型的數(shù)據(jù),聲明時需要指定通道的類型。chan Type 表示 Type 類型的通道。通道的零值為 nil 。

var channel_name chan channel_types 
var str chan string 

通道的初始化

聲明完通道后,通道的值為 nil ,不能直接使用,使用 make 函數(shù)對通道進(jìn)行初始化操作。

channel_name = make(chan channel_type) 
str = make(chan string) 

或者

str := make(chan string) 

發(fā)送和接收數(shù)據(jù)

發(fā)送數(shù)據(jù),把 data 數(shù)據(jù)發(fā)送到 channel_name 通道中。

channel_name <- data 

接收數(shù)據(jù),從 channel_name 通道中接收數(shù)據(jù)到 value。

value := <- channel_name 
func PrintFunc(c chan string) {
   c <- "往通道里面?zhèn)鲾?shù)據(jù)"
}

func main() {
   str := make(chan string)
   fmt.Println("start")
   go PrintFunc(str)
   result := <-str
   fmt.Println(result)
   fmt.Println("end")
}

發(fā)送與接收默認(rèn)是阻塞的。如果從通道接收數(shù)據(jù)沒接收完主協(xié)程是不會繼續(xù)執(zhí)行下去的。當(dāng)把數(shù)據(jù)發(fā)送到通道時,會在發(fā)送數(shù)據(jù)的語句處發(fā)生阻塞,直到有其它協(xié)程從通道讀取到數(shù)據(jù),才會解除阻塞。與此類似,當(dāng)讀取通道的數(shù)據(jù)時,如果沒有其它的協(xié)程把數(shù)據(jù)寫入到這個通道,那么讀取過程就會一直阻塞著。

通道的關(guān)閉

對于一個已經(jīng)使用完畢的通道,我們要將其進(jìn)行關(guān)閉。對于一個已經(jīng)關(guān)閉的通道如果再次關(guān)閉會導(dǎo)致報錯。

close(channel_name) 

可以在接收數(shù)據(jù)時,判斷通道是否已經(jīng)關(guān)閉,從通道讀取數(shù)據(jù)返回的第二個值表示通道是否沒被關(guān)閉,如果已經(jīng)關(guān)閉,返回值為 false ;如果還未關(guān)閉,返回值為 true 。

value, ok := <- channel_name 

通道的容量與長度

通道可以設(shè)置緩沖區(qū),通過 make 的第二個參數(shù)指定緩沖區(qū)大小

ch := make(chan int, 100)
  • 0:通道中不能存放數(shù)據(jù),在發(fā)送數(shù)據(jù)時,必須要求立馬接收,否則會報錯。此時的通道稱之為無緩沖通道。
  • 1:通道只能緩存一個數(shù)據(jù),若通道中已有一個數(shù)據(jù),此時再往里發(fā)送數(shù)據(jù),會造成程序阻塞。利用這點可以利用通道來做鎖。
  • 大于 1 :通道中可以存放多個數(shù)據(jù),可以用于多個協(xié)程之間的通信管道,共享資源。

通過 cap 函數(shù)和 len 函數(shù)獲取通道的容量和長度。

func main() {
   // 創(chuàng)建一個通道
   c := make(chan int, 5)
   fmt.Println("初始化:")
   fmt.Println("cap:", cap(c))
   fmt.Println("len:", len(c))
   c <- 1
   c <- 2
   c <- 3
   fmt.Println("傳入數(shù)據(jù):")
   fmt.Println("cap:", cap(c))
   fmt.Println("len:", len(c))
   <-c
   fmt.Println("取出一個數(shù):")
   fmt.Println("cap:", cap(c))
   fmt.Println("len:", len(c))
}

緩沖通道與無緩沖通道

帶緩沖區(qū)的通道允許發(fā)送端的數(shù)據(jù)發(fā)送和接收端的數(shù)據(jù)獲取處于異步狀態(tài),就是說發(fā)送端發(fā)送的數(shù)據(jù)可以放在緩沖區(qū)里面,可以等待接收端去獲取數(shù)據(jù),而不是立刻需要接收端去獲取數(shù)據(jù)。

不過由于緩沖區(qū)的大小是有限的,所以還是必須有接收端來接收數(shù)據(jù)的,否則緩沖區(qū)一滿,數(shù)據(jù)發(fā)送端就無法再發(fā)送數(shù)據(jù)了。

通道不帶緩沖,發(fā)送方會阻塞直到接收方從通道中接收了值。如果通道帶緩沖,發(fā)送方則會阻塞直到發(fā)送的值被拷貝到緩沖區(qū)內(nèi);如果緩沖區(qū)已滿,則意味著需要等待直到某個接收方獲取到一個值。接收方在有值可以接收之前會一直阻塞。

c := make(chan int) 
// 或者 
c := make(chan int, 0) 

緩沖通道允許通道里存儲一個或多個數(shù)據(jù),設(shè)置緩沖區(qū)后,發(fā)送端和接收端可以處于異步的狀態(tài)。

c := make(chan int, 3) 

雙向通道和單向通道

雙向通道:既可以發(fā)送數(shù)據(jù)也可以接收數(shù)據(jù)

func main() {
   // 創(chuàng)建一個通道
   c := make(chan int)

   // 發(fā)送數(shù)據(jù)
   go func() {
      fmt.Println("send: 1")
      c <- 1
   }()

   // 接收數(shù)據(jù)
   go func() {
      n := <-c
      fmt.Println("receive:", n)
   }()

   // 主協(xié)程休眠
   time.Sleep(time.Millisecond)
}

單向通道:只能發(fā)送或者接收數(shù)據(jù)。具體細(xì)分為只讀通道和只寫通道。

<-chan 表示只讀通道:

// 定義只讀通道
c := make(chan string)
// 定義類型
type Receiver = <-chan string
var receiver Receiver = c

// 或者簡單寫成下面的形式
type Receiver = <-chan int
receiver := make(Receiver)

chan<- 表示只寫通道:

// 定義只寫通道
c := make(chan int)
// 定義類型
type Sender = chan<- int
var sender Sender = c

// 或者簡單寫成下面的形式
type Sender = chan<- int
sender := make(Sender)
package main

import (
   "fmt"
   "time"
)

// Sender 只寫通道類型
type Sender = chan<- string

// Receiver 只讀通道類型
type Receiver = <-chan string

func main() {
   // 創(chuàng)建一個雙向通道
   var ch = make(chan string)

   // 開啟一個協(xié)程
   go func() {
      // 只寫通道
      var sender Sender = ch
      fmt.Println("write only start:")
      sender <- "Go"
   }()

   // 開啟一個協(xié)程
   go func() {
      // 只讀通道
      var receiver Receiver = ch
      message := <-receiver
      fmt.Println("readonly start: ", message)
   }()

   time.Sleep(time.Millisecond)
}

遍歷通道

使用 for range 循環(huán)可以遍歷通道,但在遍歷時要確保通道是處于關(guān)閉狀態(tài),否則循環(huán)會被阻塞。

package main

import (
   "fmt"
)

func loopPrint(c chan int) {
   for i := 0; i < 10; i++ {
      c <- i
   }
   // 記得要關(guān)閉通道
   // 否則主協(xié)程遍歷完不會結(jié)束,而會阻塞
   close(c)
}

func main() {
   // 創(chuàng)建一個通道
   var ch2 = make(chan int, 5)
   go loopPrint(ch2)
   for v := range ch2 {
      fmt.Println(v)
   }
}

fibonacci 數(shù)列

package main

import (
   "fmt"
)

func fibonacci(n int, c chan int) {
   x, y := 0, 1
   for i := 0; i < n; i++ {
      c <- x
      x, y = y, x+y
   }
   close(c)
}

func main() {
   c := make(chan int, 10)
   go fibonacci(cap(c), c)
   // range 函數(shù)遍歷每個從通道接收到的數(shù)據(jù),因為 c 在發(fā)送完 10 個
   // 數(shù)據(jù)之后就關(guān)閉了通道,所以這里我們 range 函數(shù)在接收到 10 個數(shù)據(jù)
   // 之后就結(jié)束了。如果上面的 c 通道不關(guān)閉,那么 range 函數(shù)就不
   // 會結(jié)束,從而在接收第 11 個數(shù)據(jù)的時候就阻塞了。
   for i := range c {
      fmt.Println(i)
   }
}

參考文章:

go-edu.cn/

www.runoob.com/go/go-tutor…

總結(jié)

到此這篇關(guān)于Go語言入門學(xué)習(xí)之Channel通道的文章就介紹到這了,更多相關(guān)Go語言Channel通道內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang中map的三種聲明定義方式實現(xiàn)

    Golang中map的三種聲明定義方式實現(xiàn)

    本文主要介紹了Golang中map的三種聲明定義方式實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Go語言sync.Cond基本使用及原理示例詳解

    Go語言sync.Cond基本使用及原理示例詳解

    這篇文章主要為大家介紹了Go語言sync.Cond基本使用及原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 一文帶你使用Golang實現(xiàn)SSH客戶端

    一文帶你使用Golang實現(xiàn)SSH客戶端

    SSH?全稱為?Secure?Shell,是一種用于安全地遠(yuǎn)程登錄到網(wǎng)絡(luò)上的其他計算機的網(wǎng)絡(luò)協(xié)議,本文主要為大家詳細(xì)介紹了如何使用?Golang?實現(xiàn)?SSH?客戶端,需要的可以參考下
    2023-11-11
  • golang 實現(xiàn)interface{}轉(zhuǎn)其他類型操作

    golang 實現(xiàn)interface{}轉(zhuǎn)其他類型操作

    這篇文章主要介紹了golang 實現(xiàn)interface{}轉(zhuǎn)其他類型操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go1.21新增slices包的用法詳解

    Go1.21新增slices包的用法詳解

    Go?1.21新增的?slices?包提供了很多和切片相關(guān)的函數(shù),可以用于任何類型的切片,這篇文章主要來和大家介紹一下slices包中相關(guān)函數(shù)的用法,需要的可以參考一下
    2023-08-08
  • Go語言基礎(chǔ)學(xué)習(xí)之Context的使用詳解

    Go語言基礎(chǔ)學(xué)習(xí)之Context的使用詳解

    在Go語言中,Context是一個非常重要的概念,它用于在不同的?goroutine?之間傳遞請求域的相關(guān)數(shù)據(jù),本文將深入探討Go語言中?Context特性和Context的高級使用方法,希望對大家有所幫助
    2023-05-05
  • golang實現(xiàn)unicode轉(zhuǎn)換為字符串string的方法

    golang實現(xiàn)unicode轉(zhuǎn)換為字符串string的方法

    這篇文章主要介紹了golang實現(xiàn)unicode轉(zhuǎn)換為字符串string的方法,實例分析了Go語言編碼轉(zhuǎn)換的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • go之如何設(shè)置GOROOT和GOPATH

    go之如何設(shè)置GOROOT和GOPATH

    這篇文章主要介紹了go之如何設(shè)置GOROOT和GOPATH問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 淺析Golang開發(fā)中g(shù)oroutine的正確使用姿勢

    淺析Golang開發(fā)中g(shù)oroutine的正確使用姿勢

    很多初級的Gopher在學(xué)習(xí)了goroutine之后,在項目中其實使用率不高,所以這篇文章小編主要來帶大家深入了解一下goroutine的常見使用方法,希望對大家有所幫助
    2024-03-03
  • Golang實現(xiàn)Json分級解析及數(shù)字解析實踐詳解

    Golang實現(xiàn)Json分級解析及數(shù)字解析實踐詳解

    你是否遇到過在無法準(zhǔn)確確定json層級關(guān)系的情況下對json進(jìn)行解析的需求呢?本文就來和大家介紹一次解析不確定的json對象的經(jīng)歷,以及遇到的問題和解決方法
    2023-02-02

最新評論