Go語言使用Channel在goroutine併發程序中傳遞資料。
Channel是用來發送及接受指定型態值的管道,使用關鍵字chan
宣告,後接傳遞資料的型態。例如下面宣告一個空的channel資料型態為string
。
var c chan string // declare c as channel with string type
fmt.Println(c) // <nil>
通常使用make()
函式建立channel。
c := make(chan string) // create channel c with string type
使用channel <- value
把值放入channel,稱為send statements。
c <- "hello" // send value "hello" to channel c
使用<-channel
接收channel中的值,稱為receive operators。
s := <-c // receive value from channel c then assign to variable s
channel值的收發預設會阻塞(block)直到另一動作可行。也就是說,如果goroutine A發送一個值給channel,但另一個goroutine B一直沒有從channel接收,則A的發送會被阻塞,直到B可接收後A的發送才會繼續。
下面範例在main程式中新增一個goroutine呼叫send()
函式並發送值進channel,並在main的goroutine接收並印出,也就是說main goroutine和send goroutine使用channel來傳遞字串。
package main
import (
"fmt"
)
func send(s string, c chan string) {
c <- s // send s to channel c
}
func main() {
c := make(chan string) // create channel c
go send("hello", c)
s := <-c // receive value from channel c
fmt.Println(s) // hello
}
而下面範例則在receive goroutine與send goroutine中以channel傳遞。main最後的time.Sleep()
是為了防止main goroutine先結束,因為main goroutine先結束會直接離開整個程序而看不出receive goroutine與send goroutine的互動。
main.go
package main
import (
"fmt"
"time"
)
func send(s string, c chan string) {
fmt.Println("send...")
c <- s
}
func receive(c chan string) {
fmt.Println("receive...")
fmt.Println(<-c)
}
func main() {
c := make(chan string)
go receive(c)
go send("hello", c)
time.Sleep(time.Second * 1)
}
可能印出以下結果。
send...
receive...
hello
或印出以下,由此可看出channel的發收的阻塞效果。
receive...
send...
hello
而Channel可使用Go內建函式close()
關閉。Channel關閉後則不可再送資料到Channel,否則會出現panic錯誤。
例如下面發送"hello"到Channel後以close()
關閉。
main.go
package main
import (
"fmt"
"time"
)
func send(s string, c chan string) {
fmt.Println("send...")
c <- s
}
func receive(c chan string) {
fmt.Println("receive...")
fmt.Println(<-c)
}
func main() {
c := make(chan string)
go receive(c)
go send("hello", c)
time.Sleep(time.Second * 1)
close(c)
go send("world" c)
time.Sleep(time.Second * 1)
}
上面Channel關閉後再發送"world"到Channel則發生panic: send on closed channel
錯誤。
沒有留言:
張貼留言