Channel:Goroutine和Goroutine之间的双向通道。
Channel是一等公民,可以作为参数,也可以作为返回值。
示例一:
在这段代码中,c是主程序和worker()这两个Goroutine之间的双向通道。
package main
import "fmt"
func worker(c chan int) {
for {
// 从channel收数据
n := <-c
fmt.Println(n)
}
}
func chanDemo() {
// var c chan int // 定义channel,此时c == nil
c := make(chan int) // 创建channel
go worker(c)
// 向channel发数据
c <- 1
c <- 2
time.Sleep(time.Millisecond)
}
func main() {
chanDemo()
// 1
// 2
}
示例二:
在这段代码中,通道channels[i]是主程序和worker(i, channels[i])这两个Goroutine之间的双向通道。
package main
import "fmt"
func worker(id int, c chan int) {
for {
fmt.Printf("Worker %d received %c\n", id, <-c)
}
}
func chanDemo() {
var channels [10]chan int
for i := 0; i < 10; i++ {
channels[i] = make(chan int)
go worker(i, channels[i])
}
for i := 0; i < 10; i++ {
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++ {
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
}
func main() {
chanDemo()
// Worker 0 received a
// Worker 0 received A
// Worker 4 received e
// Worker 5 received f
// Worker 6 received g
// Worker 7 received h
// Worker 8 received i
// Worker 1 received b
// Worker 1 received B
// Worker 9 received j
// Worker 3 received d
// Worker 2 received c
// Worker 2 received C
// Worker 5 received F
// Worker 3 received D
// Worker 4 received E
// Worker 7 received H
// Worker 6 received G
// Worker 8 received I
// Worker 9 received J
}
示例三:
package main
import "fmt"
func createWorker(id int) chan int {
c := make(chan int)
go func() {
for {
fmt.Printf("Worker %d received %c\n", id, <-c)
}
}()
return c
}
func chanDemo() {
var channels [10]chan int
for i := 0; i < 10; i++ {
channels[i] = createWorker(i)
}
for i := 0; i < 10; i++ {
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++ {
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
}
func main() {
chanDemo()
// Worker 0 received a
// Worker 0 received A
// Worker 4 received e
// Worker 5 received f
// Worker 6 received g
// Worker 7 received h
// Worker 8 received i
// Worker 1 received b
// Worker 1 received B
// Worker 9 received j
// Worker 3 received d
// Worker 2 received c
// Worker 2 received C
// Worker 5 received F
// Worker 3 received D
// Worker 4 received E
// Worker 7 received H
// Worker 6 received G
// Worker 8 received I
// Worker 9 received J
}
示例四:
还可以对channel进行修饰,告诉别人channel应该怎么使用:
chan<- int 表示 channel是用来送数据的,只能给该channel发数据
<-chan int 表示 channel是用来收数据的,只能从该channel收数据
package main
import "fmt"
func createWorker(id int) chan<- int {
c := make(chan int)
go func() {
for {
fmt.Printf("Worker %d received %c\n", id, <-c)
}
}()
return c
}
func chanDemo() {
var channels [10]chan<- int
for i := 0; i < 10; i++ {
channels[i] = createWorker(i)
}
for i := 0; i < 10; i++ {
channels[i] <- 'a' + i
}
for i := 0; i < 10; i++ {
channels[i] <- 'A' + i
}
time.Sleep(time.Millisecond)
}
func main() {
chanDemo()
// Worker 0 received a
// Worker 0 received A
// Worker 4 received e
// Worker 5 received f
// Worker 6 received g
// Worker 7 received h
// Worker 8 received i
// Worker 1 received b
// Worker 1 received B
// Worker 9 received j
// Worker 3 received d
// Worker 2 received c
// Worker 2 received C
// Worker 5 received F
// Worker 3 received D
// Worker 4 received E
// Worker 7 received H
// Worker 6 received G
// Worker 8 received I
// Worker 9 received J
}
Buffered channel:
channel还可以设置缓冲区
package main
import "fmt"
func worker(id int, c chan int) {
for {
fmt.Printf("Worker %d received %c\n", id, <-c)
}
}
func createWorker(id int) chan<- int {
c := make(chan int)
go worker(id, c)
return c
}
func bufferedChannel() {
c := make(chan int, 3)
// 缓冲区大小为3,可以往里面发三个数而不需要人收,提升性能
go worker(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
c <- 'd'
time.Sleep(time.Millisecond)
}
func main() {
bufferedChannel()
// Worker 0 received a
// Worker 0 received b
// Worker 0 received c
// Worker 0 received d
}
Channel close:
发送方可以close channel,以通知接收方没有新数据要发送了
package main
import "fmt"
func worker(id int, c chan int) {
// 当发送方close channel时,接收方仍然能接收到数据,接收的是channel里数据类型的零值,
// 如int类型为0,string类型为空串
// 当发送方close channel时,接收方有两种应对策略
// 方法1:用ok变量来判断channel是否close
for {
n, ok := <- c
if !ok {
break
}
fmt.Printf("Worker %d received %d\n", id, n)
}
// 方法2:使用range
for n := range c {
fmt.Printf("Worker %d received %d\n", id, n)
}
}
func createWorker(id int) chan<- int {
c := make(chan int)
go worker(id, c)
return c
}
func channelClose() {
c := make(chan int)
go worker(0, c)
c <- 'a'
c <- 'b'
c <- 'c'
c <- 'd'
close(c)
time.Sleep(time.Millisecond)
}
func main() {
channelClose()
// Worker 0 received 97
// Worker 0 received 98
// Worker 0 received 99
// Worker 0 received 100
}
channel的设计理念:
不要通过共享内存来通信;通过通信来共享内存。