在 Golang 中,Channel 是一种强大的并发原语,用于在不同的 goroutine 之间进行通信和同步。本文将从简单的 Channel 用法开始,逐步深入,介绍如何使用 Channel 实现并发控制、数据传递以及更复杂的通信模式。
1. 创建和基本操作
1.1 创建 Channel
package main
import (
"fmt"
)
func main() {
// 创建一个整型的 Channel
ch := make(chan int)
// 启动一个 goroutine,向 Channel 发送数据
go func() {
ch <- 42
}()
// 从 Channel 接收数据
value := <-ch
fmt.Println(value)
}
1.2 关闭 Channel
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
defer close(ch) // 关闭 Channel
ch <- 42
}()
// 使用 for 循环从 Channel 中接收数据
for value := range ch {
fmt.Println(value)
}
}
2. 单向 Channel
2.1 单向发送 Channel
package main
import "fmt"
func sendData(ch chan<- int) {
ch <- 42
}
func main() {
ch := make(chan int)
go sendData(ch)
// 从 Channel 中接收数据
value := <-ch
fmt.Println(value)
}
2.2 单向接收 Channel
package main
import "fmt"
func receiveData(ch <-chan int) {
value := <-ch
fmt.Println(value)
}
func main() {
ch := make(chan int)
go receiveData(ch)
// 向 Channel 发送数据
ch <- 42
}
3. Select 语句
3.1 多 Channel Select
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(2 * time.Second)
ch1 <- 42
}()
go func() {
time.Sleep(1 * time.Second)
ch2 <- 84
}()
// 使用 select 语句监听多个 Channel
select {
case value := <-ch1:
fmt.Println("Received from ch1:", value)
case value := <-ch2:
fmt.Println("Received from ch2:", value)
}
}
3.2 Timeout Select
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
time.Sleep(2 * time.Second)
ch <- 42
}()
// 使用 select 实现超时处理
select {
case value := <-ch:
fmt.Println("Received:", value)
case <-time.After(1 * time.Second):
fmt.Println("Timeout")
}
}
4. 带缓冲的 Channel
4.1 创建带缓冲的 Channel
package main
import "fmt"
func main() {
// 创建一个容量为 3 的带缓冲的 Channel
ch := make(chan int, 3)
// 向 Channel 发送数据
ch <- 1
ch <- 2
ch <- 3
// 从 Channel 中接收数据
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
4.2 遍历带缓冲的 Channel
package main
import "fmt"
func main() {
ch := make(chan int, 3)
// 向 Channel 发送数据
ch <- 1
ch <- 2
ch <- 3
// 遍历带缓冲的 Channel
for value := range ch {
fmt.Println(value)
}
}
5. Worker Pool 示例
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 5)
results := make(chan int, 5)
// 启动多个 worker
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func
(workerID int) {
defer wg.Done()
worker(workerID, jobs, results)
}(i)
}
// 发送任务到 jobs Channel
for i := 1; i <= 5; i++ {
jobs <- i
}
close(jobs)
// 从 results Channel 获取结果
go func() {
wg.Wait()
close(results)
}()
// 输出结果
for result := range results {
fmt.Println("Result:", result)
}
}
这篇文章涵盖了 Golang 中 Channel 的基本使用、单向 Channel、Select 语句和带缓冲的 Channel 等方面,以及一个实际的 Worker Pool 示例。希望这些例子能够帮助你更好地理解和应用 Golang 中的并发编程。