返回

协程+channel:交替打印100以内的奇偶数,玩转多线程编程

后端

协程与 Channel:解锁 Go 语言并发的强大功能

在 Go 语言中,协程和 Channel 是构建高性能并发应用程序的重要工具。协程类似于轻量级的线程,允许我们轻松地并行执行任务。Channel 提供了一种协程之间通信的管道,从而实现了数据共享和同步。

协程:并发编程的轻量级英雄

协程就像微型线程,但它们的创建和切换成本要低得多。这使得 Go 语言能够以极低的开销实现高度并发。与线程不同,协程在同一个内存空间中运行,这意味着它们可以轻松地共享数据。

Channel:协程之间的通信桥梁

Channel 是协程之间交换数据的管道。它们可以是带缓冲的或无缓冲的。带缓冲的 Channel 可以存储多个值,而无缓冲的 Channel 一次只能存储一个值。

实现交替打印奇偶数

为了展示协程和 Channel 的实际应用,让我们尝试实现一个程序,它使用两个协程交替打印 100 以内的奇偶数。我们将使用无缓冲 Channel 作为协程之间的锁。

代码示例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    // 创建一个无缓冲的 Channel
    ch := make(chan struct{})

    // 创建两个协程
    wg := sync.WaitGroup{}
    wg.Add(2)

    go func() {
        defer wg.Done()
        for i := 1; i <= 100; i += 2 {
            // 从 Channel 接收数据
            <-ch

            // 打印奇数
            fmt.Println(i)

            // 向 Channel 发送数据
            ch <- struct{}{}
        }
    }()

    go func() {
        defer wg.Done()
        for i := 2; i <= 100; i += 2 {
            // 向 Channel 发送数据
            ch <- struct{}{}

            // 打印偶数
            fmt.Println(i)

            // 从 Channel 接收数据
            <-ch
        }
    }()

    // 等待两个协程完成
    wg.Wait()
}

运行结果:

1
2
3
4
5
6
...
97
98
99
100

在这个示例中,无缓冲 Channel 确保了两个协程严格交替执行,从而实现了奇偶数的交替打印。

协程和 Channel 的优势

  • 高并发性: 协程允许我们创建大量的轻量级并发任务,从而提高应用程序的吞吐量。
  • 低开销: 协程的创建和切换成本很低,这使得我们能够以极低的资源消耗实现并发。
  • 数据共享: 协程在同一个内存空间中运行,这简化了数据共享并减少了复制开销。
  • 灵活性: Channel 提供了一种灵活的方式来控制协程之间的通信和同步。

常见问题解答

1. 协程和 goroutine 有什么区别?
答:协程和 goroutine 是同一个概念在 Go 语言中的两种说法。

2. Channel 的缓冲有什么好处?
答:带缓冲的 Channel 可以存储多个值,这可以在生产者和消费者协程之间提供缓冲,防止阻塞。

3. 如何关闭 Channel?
答:可以使用 close() 函数关闭 Channel,这将阻止进一步向 Channel 写入数据。

4. 协程和线程有什么区别?
答:协程比线程更轻量级,它们在同一个内存空间中运行。线程需要自己的堆栈,而协程共享同一个堆栈。

5. 如何防止协程死锁?
答:确保协程以适当的顺序发送和接收数据,并避免无限循环或相互依赖关系。