Golang 併發程式設計(channel實現)
上期我們使用 sync
實現方式支援協程(goroutine)併發。
接下來繼續使用下載檔案例子,使用 channel
實現併發
package main
import (
"fmt"
"sync"
"time"
)
func main() {
// ============== channel ==============
startTime2 := time.Now()
testChannel()
endTime2 := time.Now()
fmt.Printf("======> Done! use time: %f",(endTime2.Sub(startTime2).Seconds()))
fmt.Println()
}
// 使用 channel 通道,可以在協程之間傳遞訊息。等待併發協程返回訊息。
var ch = make(chan string, 10) // 建立大小 10 的快取通道
func testChannel() {
for i := 0; i 3; i++ {
go downloadV2("a.com/" + string(i+'0'))
}
for i := 0; i 3; i++ {
msg := ch // 等待通道返回訊息。
fmt.Println("finish", msg)
}
}
// ================= 工具 V =================
func downloadV2(url string) {
fmt.Println("start to download", url)
time.Sleep(time.Second)
ch url // 將 url 傳送給通道
}
channel (通道)
channel
就是 goroutine
之間的通訊機制。每個 channel 都有一個特殊的型別,也就是 channels 可傳送資料的型別。一個可以傳送 int 型別資料的 channel 一般寫為 chan int。
Golang 提倡使用 通訊的方法代替共享記憶體
,當一個資源需要在 goroutine 之間共享時,通道在 goroutine 之間架起了一個管道,並提供了確保同步交換資料的機制。
宣告通道時,需要指定被共享的資料的型別
。可以透過通道共享內建型別、命名型別、結構型別和引用型別的值或者指標。
宣告通道型別
宣告通道時,需要指定被共享的資料的型別
,宣告channel
語法如下:var 通道變數 chan 通道型別
- 通道型別:
通道內傳輸
的資料的型別 - chan 型別的空值是 nil,宣告後需要配合
make
後才能使用。
建立通道
通道是引用型別,需要使用 make 進行建立,格式如下:通道例項 := make(chan 資料型別)
資料型別:通道內被傳輸的資料的型別
。
通道例項:透過make
建立的通道控制程式碼。
舉個例子:
ch1 := make(chan int) // 建立一個整型型別的通道
ch2 := make(chan interface{}) // 建立一個空介面型別的通道, 可以存放任意格式
type Equip struct{ /* 一些欄位 */ }
ch2 := make(chan *Equip) // 建立Equip指標型別的通道, 可以存放*Equip
使用通道傳送資料
通道建立後,就可以使用通道進行傳送和接收操作。
通道傳送資料的格式
通道的傳送使用特殊的運算子,將資料透過通道傳送的格式為:
通道變數
- 通道變數:透過make建立好的通道例項。
- 值:可以是變數、常量、表示式或者函式返回值等。
值的型別
必須與ch通道
的元素型別一致
。
使用 make 建立一個通道後,就可以使用
// 建立一個空介面通道
ch := make(chan interface{})
// 將0放入通道中
ch 0
// 將hello字串放入通道中
ch "hello"
傳送將持續阻塞直到資料被接收
把資料往通道中傳送時,如果接收方一直沒接收
,那麼傳送操作將持續阻塞
。
Go 程式執行時能智慧地發現一些永遠無法傳送成功的語句並做出提示,程式碼如下:
package main
func main() {
// 建立一個整型通道
ch := make(chan int)
// 嘗試將0透過通道傳送
ch 0
}
執行程式碼,報錯:
fatal error: all goroutines are asleep - deadlock!
報錯的意思是:執行時發現所有的 goroutine(包括main)都處於等待 goroutine。
也就是說所有 goroutine 中的 channel 並沒有形成傳送和接收對應的程式碼。
使用通道接收資料
通道接收同樣使用運算子,通道接收有如下特性:
-
通道的收發操作在不同的兩個 goroutine 間進行。
由於通道的資料在沒有接收方處理時,資料傳送方會持續阻塞,因此通道的接收必定在另外一個 goroutine 中進行。 -
接收將持續阻塞直到傳送方傳送資料。
如果接收方接收時,通道中沒有傳送方傳送資料,接收方也會發生阻塞,直到傳送方傳送資料為止。 -
每次接收一個元素。
通道一次只能接收一個資料元素。
通道的資料接收一共有以下 4 種寫法:
阻塞接收資料
阻塞模式接收資料時,將接收變數作為data :=
執行該語句時將會阻塞,直到接收到資料並賦值給 data 變數。
非阻塞接收資料
使用非阻塞方式從通道接收資料時,語句不會發生阻塞,格式如下:data, ok :=
- data:表示接收到的資料。未接收到資料時,data 為通道型別的零值。
- ok:表示是否接收到資料。
非阻塞
的通道接收方法可能造成更高 CPU 佔用
,因此使用非常少。如果需要實現接收超時檢測,可以配合 select 和計數 channel 進行,可以參見後面的內容。
接收任意資料,忽略接收的資料
阻塞接收資料後,忽略從通道返回的資料,格式如下:
執行該語句時將會發生阻塞,直到接收到資料,但接收到的資料會被忽略。這個方式實際上只是透過通道在 goroutine 間阻塞收發實現併發同步。
使用通道做併發同步的寫法,可以參考下面的例子:
package main
import (
"fmt"
)
func main() {
// 構建一個通道
ch := make(chan int)
// 開啟一個併發匿名函式
go func() {
fmt.Println("start goroutine")
// 透過通道通知main的goroutine
ch 0
fmt.Println("exit goroutine")
}()
fmt.Println("wait goroutine")
// 等待匿名goroutine
ch
fmt.Println("all done")
}
// 輸出如下:
// wait goroutine
// start goroutine
// exit goroutine
// all done
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4729/viewspace-2797138/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Golang併發程式設計——goroutine、channel、syncGolang程式設計
- Golang 併發程式設計實踐Golang程式設計
- Golang併發程式設計程式通訊channel瞭解及簡單使用Golang程式設計
- Golang 併發程式設計Golang程式設計
- golang併發程式設計Golang程式設計
- 十.Go併發程式設計--channel使用Go程式設計
- Golang併發程式設計有緩衝通道和無緩衝通道(channel)Golang程式設計
- 理解Golang併發程式設計Golang程式設計
- Golang Channel 高併發的初始Golang
- Golang併發程式設計基礎Golang程式設計
- 如何理解golang的併發程式設計Golang程式設計
- 「Golang成長之路」併發之Channel下Golang
- 「Golang成長之路」併發之Channel上Golang
- JAVA實現網路程式設計之併發程式設計Java程式設計
- 如何將golang的併發程式設計運用到實際開發Golang程式設計
- 「Golang成長之路」併發之channel篇2Golang
- Java併發程式設計:Synchronized及其實現原理Java程式設計synchronized
- 《java併發程式設計的藝術》併發底層實現原理Java程式設計
- TCP併發伺服器的程式設計實現TCP伺服器程式設計
- Java併發程式設計 - 第十一章 Java併發程式設計實踐Java程式設計
- Java併發程式設計實踐Java程式設計
- Java併發程式設計實戰Java程式設計
- 【面試實戰】# 併發程式設計面試程式設計
- 玩轉Golang的channel,二百行程式碼實現PubSub模式Golang行程模式
- go併發 - channelGo
- Golang併發程式設計中select簡單瞭解Golang程式設計
- golang 併發程式設計之生產者消費者Golang程式設計
- golang開發:channel使用Golang
- 【併發程式設計】Future模式及JDK中的實現程式設計模式JDK
- 【Java併發程式設計】Synchronized關鍵字實現原理Java程式設計synchronized
- 併發程式設計程式設計
- Java併發程式設計實戰--FutureTaskJava程式設計
- 併發程式設計實戰——鎖分段程式設計
- 【Java併發程式設計】併發程式設計大合集-值得收藏Java程式設計
- go 併發程式設計案例三 golang 中的物件導向程式設計Golang物件
- 如何利用sockserver模組程式設計實現客戶端併發Server程式設計客戶端
- 41、併發程式設計之多程式實操篇程式設計
- 【併發程式設計】(二)Java併發機制底層實現原理——synchronized關鍵字程式設計Javasynchronized