深入理解 Golang 中 Channel 的用法:从简单到复杂

发布时间:2023年12月22日

在 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 中的并发编程。

文章来源:https://blog.csdn.net/weixin_43425950/article/details/135131633
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。