返回

Go channel 潜藏三大坑,你不踩行吗?

后端

在 Go 语言中,channel 作为一种常用的并发编程工具,常用于 goroutine 之间的通信。但使用 channel 时,会遇到各种各样的问题,本文就来梳理一下使用 channel 中常见的三大坑:panic、死锁、内存泄漏。

坑一:panic

成因:
当在 channel 上发送或接收数据时,如果 channel 处于关闭状态,就会引发 panic。

案例:

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int)
	close(ch)
	ch <- 1 // 导致 panic
}

解决方法:
在使用 channel 前,先检查 channel 是否已经关闭,如果关闭了,就不要再使用它。

坑二:死锁

成因:
死锁是指两个或多个 goroutine 相互等待对方释放资源,导致程序无法继续运行。

案例:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	ch := make(chan int)

	go func() {
		defer wg.Done()
		ch <- 1 // 等待接收方接收数据
	}()

	go func() {
		defer wg.Done()
		<-ch // 等待发送方发送数据
	}()

	wg.Wait() // 等待两个 goroutine 都结束
}

解决方法:
避免在 goroutine 中使用死锁。可以使用 select 语句来解决死锁问题。

坑三:内存泄漏

成因:
内存泄漏是指程序中分配的内存无法被释放,导致程序的内存使用量不断增加。

案例:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	ch := make(chan int)

	go func() {
		defer wg.Done()
		for {
			ch <- 1 // 不断向 channel 发送数据
		}
	}()

	go func() {
		defer wg.Done()
		for {
			<-ch // 不断从 channel 接收数据
		}
	}()

	wg.Wait() // 等待两个 goroutine 都结束
}

解决方法:
在使用 channel 时,要确保在不使用 channel 时将其关闭,以释放内存。

结语

channel 是 Go 语言中常用的并发编程工具,但使用 channel 时要小心,要避免 panic、死锁、内存泄漏等问题。