package good_pratice
import (
"fmt"
"sync"
"time"
)
// UnbufferedChannel 这个方法会出现死锁
// 无缓冲通道说明通道是没有空间的,不能暂存数据,所以必须发送和接收同时发生。要满足”同时发生“这个条件,必须放在不同协程中。
func UnbufferedChannel() {
c := make(chan int)
c <- 3
a := <-c
fmt.Printf("a:%#v\n", a)
}
//UnbufferedChannel2 正确示例
// 满足接收和发送”同时发生“
func UnbufferedChannel2() {
c := make(chan int)
go func() {
time.Sleep(time.Second * 2)
c <- 3
}()
a := <-c
fmt.Printf("a:%#v\n", a)
}
// UnbufferedChannel3 for range遍历channel
// 串行执行,并不会同时并发执行
func UnbufferedChannel3() {
c := make(chan int)
go func() {
for i := 0; i < 100; i++ {
time.Sleep(time.Second) //模拟执行耗时任务
c <- i
}
close(c) // 重点:这里发送完数据后一定要执行close关闭通道,否则打印之后会报死锁。
}()
for n := range c {
fmt.Printf("n:%#v\n", n)
}
}
//UnbufferedChannel4
//并行执行多个任务
func UnbufferedChannel4() {
c := make(chan int)
go func() {
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
temp := i
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(time.Second) //模拟执行耗时任务
c <- temp
}()
}
wg.Wait()
close(c) // 重点:这里发送完数据后一定要执行close关闭通道,否则打印之后会报死锁。
}()
for n := range c {
fmt.Printf("n:%#v\n", n)
}
}
// bufferedChannel
// 利用有缓冲通道并发执行任务,并且可以限制协程数量
func bufferedChannel() {
maxConcurrency := 3 // 定义一个最大并发数为3的通道
concurrency := make(chan struct{}, maxConcurrency)
// 模拟执行10个任务
numTasks := 10
var wg sync.WaitGroup
for i := 0; i < numTasks; i++ {
wg.Add(1)
go func(taskID int) {
defer wg.Done()
// 执行任务前获取通道中的令牌
concurrency <- struct{}{}
fmt.Printf("开始执行任务:%d\n", taskID)
// 模拟任务执行时间
time.Sleep(time.Second * 2)
fmt.Printf("完成任务:%d\n", taskID)
// 任务完成后释放通道中的令牌
<-concurrency
}(i)
}
// 等待所有任务完成
wg.Wait()
}
func ChannelTest() {
//UnbufferedChannel() //这个方法会报错:fatal error: all goroutines are asleep - deadlock!
//UnbufferedChannel2() //这个方法正确
//UnbufferedChannel3() //能够正常输出通道的数据,不过是串行执行,并不会同时并发执行。即每秒输出一个数字。100个数字耗时100秒。
//UnbufferedChannel4() //这个不仅能正常输出通道的数据,而且是并行执行,同时开100个协程执行任务,一秒内就能完成任务。不过输出的是乱序。
bufferedChannel() //有缓冲通道并发执行,还能控制协程的数量
}
go实战之channel
最新推荐文章于 2024-06-15 22:45:00 发布