Golang并发编程入门:Go与Channel详解

向北走
向北走
发布时间:2026-10-14| 3人浏览过
原创

Golang的并发模型是语言设计的亮点。本文解析如何在Go中创建轻量级线程(goroutine),并通过channel机制安全高效地进行线程间通信,最后展示如何利用select实现多任务同步。

使用go关键字开启协程

Golang运行时管理了一种被称为 goroutine 的轻量级线程。与普通操作系统线程相比,它的创建开销极小,同时运行数十万个甚至更多的 goroutine 也是可行的。要启动一个 goroutine,只需在普通函数或方法调用前加上 go 关键字即可。

package main

import (
    "fmt"
    "time"
)

// 被调用的函数
func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    // 异步执行say("world")
    go say("world")
    // 同步执行say("hello")
    say("hello")
}

通过Channel进行通讯

为了避免显式使用互斥锁来保证线程安全,Go推荐直接使用 channel 在不同 goroutine 之间传递数据。channel 是一种带有类型的管道,必须指定其收发值的类型。箭头操作符 <- 表示数据的流向:

  • 发送:ch <- v(将 v 发送到 ch)。
  • 接收:v := <-ch(从 ch 接收值赋给 v)。

发送和接收默认是阻塞的。通过 make 函数可以创建 channel,语法为 make(chan 数据类型)。

实例:分割数组求和

以下代码演示了如何将一个数组拆分为两部分,开启两个 goroutine 并行计算部分和,最后在主线程汇总结果:

package main

import "fmt"

// sum 函数计算数组元素之和,并将结果写入 channel
func sum(a []int, c chan int) {
    s := 0
    for _, v := range a {
        s += v
    }
    c <- s // 发送结果
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    // 创建接收 int 的 channel
    c := make(chan int)

    // 并行计算数组前半部分
    go sum(a[:len(a)/2], c)
    // 并行计算数组后半部分
    go sum(a[len(a)/2:], c)

    // 阻塞等待两个结果
    x, y := <-c, <-c

    fmt.Println(x, y, x+y)
}

带缓冲的Channel与关闭

channel 可以通过第二个参数设置缓冲区长度。发送时仅在缓冲区满时才阻塞,接收时仅在缓冲区空时才阻塞:

// 创建长度为2的缓冲channel
ch := make(chan int, 2)
ch <- 1
ch <- 2 // 此时不阻塞
fmt.Println(<-ch)

当发送者不再发送数据时,可以调用 close(ch) 关闭通道。注意:严禁向已关闭的 channel 发送值,否则会引发 panic;向已关闭且有缓冲的 channel 接收值时,先取走剩余值,然后均返回该类型的零值。

为了配合循环取值,for range 结构非常实用。它可以自动遍历 channel 的值,直到 channel 被关闭为止:

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c) // 发送完毕后必须关闭
}

func main() {
    c := make(chan int)
    go fibonacci(10, c)

    // 自动遍历直至关闭
    for i := range c {
        fmt.Println(i)
    }
}

利用Select处理多路复用

当一个 goroutine 需要监听多个 channel 通讯时,可以使用 select 语句。它会阻塞直到某个 case 能够运行。如果多个 case 同时满足,则随机选择一个执行。

select 还支持一个可选的 default 分支。如果没有任何 case 准备好,立即执行 default,从而实现非阻塞检查或超时逻辑:

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(100 * time.Millisecond)
    boom := time.After(500 * time.Millisecond)

    for {
        select {
        case <-tick:
            fmt.Println("tick.")
        case <-boom:
            fmt.Println("BOOM!")
            return
        default:
            fmt.Println("...")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

总结

掌握 goroutine 的创建以及 channel 的基本收发操作是理解 Go 并发的第一步。合理使用缓冲机制可以提升性能,而 select 则是解决复杂并发协作问题的关键工具。以上就是 Golang 并发编程基础支持的详细内容,更多关于 Golang 并发控制机制的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。