日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
創(chuàng)新互聯(lián)GO教程:Go語言通道(chan)——goroutine之間通信的管道

如果說 goroutine 是 Go語言程序的并發(fā)體的話,那么 channels 就是它們之間的通信機(jī)制。一個 channels 是一個通信機(jī)制,它可以讓一個 goroutine 通過它給另一個 goroutine 發(fā)送值信息。每個 channel 都有一個特殊的類型,也就是 channels 可發(fā)送數(shù)據(jù)的類型。一個可以發(fā)送 int 類型數(shù)據(jù)的 channel 一般寫為 chan int。

10年的亞東網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整亞東建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)從事“亞東網(wǎng)站設(shè)計”,“亞東網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。

Go語言提倡使用通信的方法代替共享內(nèi)存,當(dāng)一個資源需要在 goroutine 之間共享時,通道在 goroutine 之間架起了一個管道,并提供了確保同步交換數(shù)據(jù)的機(jī)制。聲明通道時,需要指定將要被共享的數(shù)據(jù)的類型??梢酝ㄟ^通道共享內(nèi)置類型、命名類型、結(jié)構(gòu)類型和引用類型的值或者指針。

這里通信的方法就是使用通道(channel),如下圖所示。



圖:goroutine 與 channel 的通信

在地鐵站、食堂、洗手間等公共場所人很多的情況下,大家養(yǎng)成了排隊的習(xí)慣,目的也是避免擁擠、插隊導(dǎo)致的低效的資源使用和交換過程。代碼與數(shù)據(jù)也是如此,多個 goroutine 為了爭搶數(shù)據(jù),勢必造成執(zhí)行的低效率,使用隊列的方式是最高效的,channel 就是一種隊列一樣的結(jié)構(gòu)。

通道的特性

Go語言中的通道(channel)是一種特殊的類型。在任何時候,同時只能有一個 goroutine 訪問通道進(jìn)行發(fā)送和獲取數(shù)據(jù)。goroutine 間通過通道就可以通信。

通道像一個傳送帶或者隊列,總是遵循先入先出(First In First Out)的規(guī)則,保證收發(fā)數(shù)據(jù)的順序。

聲明通道類型

通道本身需要一個類型進(jìn)行修飾,就像切片類型需要標(biāo)識元素類型。通道的元素類型就是在其內(nèi)部傳輸?shù)臄?shù)據(jù)類型,聲明如下:

var 通道變量 chan 通道類型

  • 通道類型:通道內(nèi)的數(shù)據(jù)類型。
  • 通道變量:保存通道的變量。

chan 類型的空值是 nil,聲明后需要配合 make 后才能使用。

創(chuàng)建通道

通道是引用類型,需要使用 make 進(jìn)行創(chuàng)建,格式如下:

通道實例 := make(chan 數(shù)據(jù)類型)

  • 數(shù)據(jù)類型:通道內(nèi)傳輸?shù)脑仡愋汀?/li>
  • 通道實例:通過make創(chuàng)建的通道句柄。

請看下面的例子:

ch1 := make(chan int)                 // 創(chuàng)建一個整型類型的通道
ch2 := make(chan interface{})         // 創(chuàng)建一個空接口類型的通道, 可以存放任意格式

type Equip struct{ /* 一些字段 */ }
ch2 := make(chan *Equip)             // 創(chuàng)建Equip指針類型的通道, 可以存放*Equip

使用通道發(fā)送數(shù)據(jù)

通道創(chuàng)建后,就可以使用通道進(jìn)行發(fā)送和接收操作。

1) 通道發(fā)送數(shù)據(jù)的格式

通道的發(fā)送使用特殊的操作符
<-,將數(shù)據(jù)通過通道發(fā)送的格式為:

通道變量 <- 值

  • 通道變量:通過make創(chuàng)建好的通道實例。
  • 值:可以是變量、常量、表達(dá)式或者函數(shù)返回值等。值的類型必須與ch通道的元素類型一致。

2) 通過通道發(fā)送數(shù)據(jù)的例子

使用 make 創(chuàng)建一個通道后,就可以使用
<-向通道發(fā)送數(shù)據(jù),代碼如下:

// 創(chuàng)建一個空接口通道
ch := make(chan interface{})
// 將0放入通道中
ch <- 0
// 將hello字符串放入通道中
ch <- "hello"

3) 發(fā)送將持續(xù)阻塞直到數(shù)據(jù)被接收

把數(shù)據(jù)往通道中發(fā)送時,如果接收方一直都沒有接收,那么發(fā)送操作將持續(xù)阻塞。Go 程序運行時能智能地發(fā)現(xiàn)一些永遠(yuǎn)無法發(fā)送成功的語句并做出提示,代碼如下:

package main

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

    // 嘗試將0通過通道發(fā)送
    ch <- 0
}

運行代碼,報錯:

fatal error: all goroutines are asleep - deadlock!

報錯的意思是:運行時發(fā)現(xiàn)所有的 goroutine(包括main)都處于等待 goroutine。也就是說所有 goroutine 中的 channel 并沒有形成發(fā)送和接收對應(yīng)的代碼。

使用通道接收數(shù)據(jù)

通道接收同樣使用
<-操作符,通道接收有如下特性:

① 通道的收發(fā)操作在不同的兩個 goroutine 間進(jìn)行。

由于通道的數(shù)據(jù)在沒有接收方處理時,數(shù)據(jù)發(fā)送方會持續(xù)阻塞,因此通道的接收必定在另外一個 goroutine 中進(jìn)行。

② 接收將持續(xù)阻塞直到發(fā)送方發(fā)送數(shù)據(jù)。

如果接收方接收時,通道中沒有發(fā)送方發(fā)送數(shù)據(jù),接收方也會發(fā)生阻塞,直到發(fā)送方發(fā)送數(shù)據(jù)為止。

③ 每次接收一個元素。

通道一次只能接收一個數(shù)據(jù)元素。

通道的數(shù)據(jù)接收一共有以下 4 種寫法。

1) 阻塞接收數(shù)據(jù)

阻塞模式接收數(shù)據(jù)時,將接收變量作為
<-操作符的左值,格式如下:

data := <-ch

執(zhí)行該語句時將會阻塞,直到接收到數(shù)據(jù)并賦值給 data 變量。

2) 非阻塞接收數(shù)據(jù)

使用非阻塞方式從通道接收數(shù)據(jù)時,語句不會發(fā)生阻塞,格式如下:

data, ok := <-ch

  • data:表示接收到的數(shù)據(jù)。未接收到數(shù)據(jù)時,data 為通道類型的零值。
  • ok:表示是否接收到數(shù)據(jù)。

非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要實現(xiàn)接收超時檢測,可以配合 select 和計時器 channel 進(jìn)行,可以參見后面的內(nèi)容。

3) 接收任意數(shù)據(jù),忽略接收的數(shù)據(jù)

阻塞接收數(shù)據(jù)后,忽略從通道返回的數(shù)據(jù),格式如下:

<-ch

執(zhí)行該語句時將會發(fā)生阻塞,直到接收到數(shù)據(jù),但接收到的數(shù)據(jù)會被忽略。這個方式實際上只是通過通道在 goroutine 間阻塞收發(fā)實現(xiàn)并發(fā)同步。

使用通道做并發(fā)同步的寫法,可以參考下面的例子:

package main

import (
    "fmt"
)

func main() {

    // 構(gòu)建一個通道
    ch := make(chan int)

    // 開啟一個并發(fā)匿名函數(shù)
    go func() {

        fmt.Println("start goroutine")

        // 通過通道通知main的goroutine
        ch <- 0

        fmt.Println("exit goroutine")

    }()

    fmt.Println("wait goroutine")

    // 等待匿名goroutine
    <-ch

    fmt.Println("all done")

}

執(zhí)行代碼,輸出如下:

wait goroutine
start goroutine
exit goroutine
all done

代碼說明如下:

  • 第 10 行,構(gòu)建一個同步用的通道。
  • 第 13 行,開啟一個匿名函數(shù)的并發(fā)。
  • 第 18 行,匿名 goroutine 即將結(jié)束時,通過通道通知 main 的 goroutine,這一句會一直阻塞直到 main 的 goroutine 接收為止。
  • 第 27 行,開啟 goroutine 后,馬上通過通道等待匿名 goroutine 結(jié)束。

4) 循環(huán)接收

通道的數(shù)據(jù)接收可以借用 for range 語句進(jìn)行多個元素的接收操作,格式如下:

for data := range ch {

}

通道 ch 是可以進(jìn)行遍歷的,遍歷的結(jié)果就是接收到的數(shù)據(jù)。數(shù)據(jù)類型就是通道的數(shù)據(jù)類型。通過 for 遍歷獲得的變量只有一個,即上面例子中的 data。

遍歷通道數(shù)據(jù)的例子請參考下面的代碼。

使用 for 從通道中接收數(shù)據(jù):

package main

import (
    "fmt"

    "time"
)

func main() {

    // 構(gòu)建一個通道
    ch := make(chan int)

    // 開啟一個并發(fā)匿名函數(shù)
    go func() {

        // 從3循環(huán)到0
        for i := 3; i >= 0; i-- {

            // 發(fā)送3到0之間的數(shù)值
            ch <- i

            // 每次發(fā)送完時等待
            time.Sleep(time.Second)
        }

    }()

    // 遍歷接收通道數(shù)據(jù)
    for data := range ch {

        // 打印通道數(shù)據(jù)
        fmt.Println(data)

        // 當(dāng)遇到數(shù)據(jù)0時, 退出接收循環(huán)
        if data == 0 {
                break
        }
    }

}

執(zhí)行代碼,輸出如下:

3
2
1
0

代碼說明如下:

  • 第 12 行,通過 make 生成一個整型元素的通道。
  • 第 15 行,將匿名函數(shù)并發(fā)執(zhí)行。
  • 第 18 行,用循環(huán)生成 3 到 0 之間的數(shù)值。
  • 第 21 行,將 3 到 0 之間的數(shù)值依次發(fā)送到通道 ch 中。
  • 第 24 行,每次發(fā)送后暫停 1 秒。
  • 第 30 行,使用 for 從通道中接收數(shù)據(jù)。
  • 第 33 行,將接收到的數(shù)據(jù)打印出來。
  • 第 36 行,當(dāng)接收到數(shù)值 0 時,停止接收。如果繼續(xù)發(fā)送,由于接收 goroutine 已經(jīng)退出,沒有 goroutine 發(fā)送到通道,因此運行時將會觸發(fā)宕機(jī)報錯。

文章名稱:創(chuàng)新互聯(lián)GO教程:Go語言通道(chan)——goroutine之間通信的管道
文章鏈接:http://www.5511xx.com/article/cooigdd.html