Golang协程(Goroutine)与通道(Channel)教程

我刚接触Golang的并发编程,对Goroutine和Channel的使用有些困惑。请问:

  1. Goroutine和普通线程有什么区别?为什么说它更轻量级?
  2. Channel在实际项目中通常用来解决哪些问题?能不能举个典型的生产者-消费者例子?
  3. 带缓冲的Channel和不带缓冲的Channel在使用上有什么需要注意的地方?
  4. 如何避免Goroutine泄漏?有没有什么最佳实践?
  5. 当多个Goroutine同时往Channel写数据时,会发生数据竞争吗?需要加锁吗? 希望能得到一些实际代码示例和最佳实践建议,谢谢!
3 回复

Go语言的协程(Goroutine)和通道(Channel)是其核心特性。协程是一种轻量级线程,由Go runtime管理,创建成本低,调度高效。

创建协程:使用go关键字。例如:

go func() {
    fmt.Println("这是一个协程")
}()

注意,协程启动后,主函数可能已经结束,需确保协程执行完毕。

通道(Channel):用于协程间通信。定义时需指定数据类型,如chan int。支持发送(<-)和接收操作。

基本用法

  1. 声明与初始化
    ch := make(chan int)
    
  2. 发送与接收
    ch <- 42 // 发送
    value := <-ch // 接收
    
  3. 带缓冲的通道
    ch := make(chan int, 5) // 缓冲区大小为5
    

关闭通道:使用close(ch),发送方应避免在关闭后继续写入。

select语句:用于多路复用,类似switch-case。

select {
case v := <-ch:
    fmt.Println(v)
default:
    fmt.Println("通道未准备好")
}

注意事项:死锁和数据竞争是常见问题,务必确保发送与接收匹配,使用sync包避免竞态。通过这些工具,Go能高效处理并发任务。

更多关于Golang协程(Goroutine)与通道(Channel)教程的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go语言的协程(Goroutine)和通道(Channel)是其核心特性。Goroutine是轻量级线程,由Go runtime管理,通过go关键字启动,非常高效。

使用示例:

func say(s string) {
    for i := 0; i < 5; i++ {
        fmt.Println(s)
    }
}

func main() {
    go say("goroutine") // 启动一个协程
    say("main")         // 主协程继续执行
}

通道(Channel)用于协程间的通信和同步。声明格式:chan<-发送,<-chan接收。 示例:

func sum(a []int, c chan int) {
    sum := 0
    for _, v := range a {
        sum += v
    }
    c <- sum // 发送结果到通道
}

func main() {
    a := []int{2, 3, 4}
    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)
}

常用操作包括缓冲通道、关闭通道、select语句处理多通道等。记住,使用close()关闭通道,并用for-range安全读取数据,避免资源泄漏。

Golang协程(Goroutine)与通道(Channel)教程

Goroutine(协程)

Goroutine是Go语言的轻量级线程实现,由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() {
    go say("world") // 创建一个新协程
    say("hello")    // 主协程
}

Channel(通道)

Channel是Goroutine之间的通信机制,可以安全地传递数据:

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 将sum发送到通道c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}
    
    c := make(chan int) // 创建通道
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    
    x, y := <-c, <-c // 从通道接收
    
    fmt.Println(x, y, x+y)
}

通道类型

  1. 无缓冲通道:发送和接收会阻塞直到另一方准备好

    ch := make(chan int)
    
  2. 缓冲通道:可以存储有限数量的值

    ch := make(chan int, 100)
    

关闭通道

close(ch) // 关闭通道
v, ok := <-ch // ok为false表示通道已关闭

选择语句(select)

select {
case v := <-ch1:
    fmt.Println("收到", v)
case ch2 <- x:
    fmt.Println("发送", x)
default:
    fmt.Println("没有通信")
}

协程和通道是Go并发模型的核心,它们使并发编程变得简单而高效。

回到顶部