Channel 是 Go 语言中 goroutine 之间通信的管道。本章将详细介绍 Channel 的使用方法。
Channel 是一种类型安全的管道,用于在 goroutine 之间传递数据。
Channel 示意:
goroutine A ──→ ┌─────────┐ ──→ goroutine B
│ Channel │
└─────────┘
Go 的并发哲学:不要通过共享内存来通信,而要通过通信来共享内存。
package main
import "fmt"
func main() {
ch := make(chan int)
fmt.Printf("类型: %T, 值: %v\n", ch, ch)
}
ch := make(chan int) // 无缓冲
ch := make(chan int, 10) // 缓冲,容量 10
package main
import "fmt"
func main() {
ch := make(chan string)
go func() {
ch <- "Hello"
}()
msg := <-ch
fmt.Println(msg)
}
ch <- value // 发送
value := <-ch // 接收
value, ok := <-ch // 接收并检查是否关闭
无缓冲 channel 发送和接收是同步的:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
go func() {
time.Sleep(time.Second)
ch <- "完成"
}()
fmt.Println("等待...")
msg := <-ch
fmt.Println(msg)
}
缓冲 channel 在缓冲区满之前,发送不会阻塞:
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
fmt.Println("发送了 3 个值")
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
close(ch)
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for {
value, ok := <-ch
if !ok {
fmt.Println("通道已关闭")
break
}
fmt.Println(value)
}
}
package main
import "fmt"
func main() {
ch := make(chan int, 3)
go func() {
ch <- 1
ch <- 2
ch <- 3
close(ch)
}()
for value := range ch {
fmt.Println(value)
}
}
func send(ch chan<- int) {
ch <- 1
}
func receive(ch <-chan int) {
value := <-ch
fmt.Println(value)
}
package main
import "fmt"
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int) {
for value := range ch {
fmt.Printf("消费: %d\n", value)
}
}
func main() {
ch := make(chan int, 3)
go producer(ch)
consumer(ch)
}
select 用于处理多个 channel:
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
ch1 <- "from ch1"
}()
go func() {
time.Sleep(200 * time.Millisecond)
ch2 <- "from ch2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}
}
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
go func() {
time.Sleep(2 * time.Second)
ch <- "结果"
}()
select {
case msg := <-ch:
fmt.Println(msg)
case <-time.After(time.Second):
fmt.Println("超时")
}
}
package main
import "fmt"
func main() {
ch := make(chan int, 1)
select {
case ch <- 1:
fmt.Println("发送成功")
default:
fmt.Println("发送失败")
}
select {
case value := <-ch:
fmt.Printf("接收: %d\n", value)
default:
fmt.Println("没有数据")
}
}
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Printf("worker %d 处理任务 %d\n", id, job)
time.Sleep(500 * time.Millisecond)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, jobs, results, &wg)
}
for i := 1; i <= 5; i++ {
jobs <- i
}
close(jobs)
go func() {
wg.Wait()
close(results)
}()
for result := range results {
fmt.Printf("结果: %d\n", result)
}
}
package main
import (
"fmt"
"time"
)
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
fmt.Printf("生产: %d\n", i)
time.Sleep(100 * time.Millisecond)
}
close(ch)
}
func consumer(ch <-chan int, done chan<- bool) {
for value := range ch {
fmt.Printf("消费: %d\n", value)
time.Sleep(200 * time.Millisecond)
}
done <- true
}
func main() {
ch := make(chan int, 3)
done := make(chan bool)
go producer(ch)
go consumer(ch, done)
<-done
fmt.Println("完成")
}
本章学习了 Go 语言的 Channel:
| 知识点 | 说明 |
|---|---|
| 创建 | make(chan T) 或 make(chan T, n) |
| 发送 | ch <- value |
| 接收 | value := <-ch |
| 关闭 | close(ch) |
| 遍历 | for v := range ch |
| select | 多 channel 处理 |