Golang:并发任务处理器

本文介绍了如何使用Golang的并发特性处理任务。通过管道channel限制并发数量,利用sync.WaitGroup确保所有任务完成。示例展示了如何创建一个并发任务处理器,限制最大并发数为10,同时解释了缓冲区与无缓冲区管道的区别以及死锁的避免。文章还讲解了sync.WaitGroup在等待多协程完成时的作用。
摘要由CSDN通过智能技术生成

Golang:并发任务处理器

要求:给定n个task任务的数组tasks,和执行函数excute(),构造一个函数handle(),并发执行task任务,并且同一时间允许的最大并发调用数为10

内容提要:管道channel

管道的定义:

// 10个缓冲区的chan; make(chan chan类型,缓冲区大小)
var cacheCh = make(chan struct{},10)
// 无缓冲区的chan
var ch = make(chan struct{})

管道的传值:

管道变量之后使用符号<-+。即可向管道中传入值,例如:

// 向管道中插入一个空的结构体
ch <- struct{}{} 

管道的值获取:

管道变量之前使用<-表示冲管道中取值,如果管道中没有值,会阻塞

// 将从管道中获取到的值赋值到变量value中.如果没有值会阻塞直到获取到值
value := <- ch

有缓冲区和无缓冲区的区别:

当管道中的值还没有被消耗完,且管道已满。再向管道中传值会阻塞,直到缓冲区有空位。

// 定义一个两个缓冲区的管道,然后插入3次值
ch2 := make(chan int, 2)
// 向管道中传值
go func() {
    for i := 1; i <= 3; i++ {
        ch2 <- i
        fmt.Println("插入成功")
    }
}()
time.Sleep(time.Second * 3)
fmt.Println("等待3秒。。。取出一个")
<-ch2
// 防止程序提前退出,sleep 1 秒
time.Sleep(time.Second * 1)

// 第三次插入因为没有缓冲区了,会阻塞3秒
/* 输出结果:

插入成功
插入成功
等待3秒。。。取出一个
插入成功
*/ 

无缓冲区的死锁:

// 定义一个无缓冲区的chan
ch := make(chan struct{})
// 向管道传值
ch <- struct{}{}
fmt.Println("插入成功")
// 取值
<-ch
fmt.Println("取出成功")
/* 输出:
fatal error: all goroutines are asleep - deadlock!
*/
// 无缓冲区就要求传值和接收值必须都准备好

无缓冲区,但是由协程异步传值,不会死锁

// 定义一个无缓冲区的chan
ch := make(chan int)
// 向管道传值
go func() {	
	// 必须在协程中,如果是同步的话会死锁
    ch <- struct{}{}
    fmt.Println("插入成功")
}()
// 取值
<-ch
fmt.Println("取出成功")
/*输出结果:

插入成功
取出成功
*/

内容提要:sync.WatiGroup{}

用于等待多个协程处理完返回结果。例如有个请求过来,需要去读取数据库、还有操作文件、请求第三方接口,为了加快处理数据,你选择了将这些异步出来,独立执行,最后都处理完后将结果整合返回。

这里会有个问题,你无法感知异步任务执行情况怎么样了,如果有的任务还没处理完主程序就返回了,结果会不完整。不符合预期。

sync.WatiGroup{}可以解决这个等待问题。

  1. WatiGroup.Add(num int)可以添加等待的任务数,num表示任务个数

  2. WatiGroup.Done()执行后表示一个任务处理完毕

  3. WatiGroup.Wait()会阻塞,直到所有的任务都Done处理完毕。

异步处理三个耗时任务,等待所有任务处理完毕返回结果:

wg := sync.WaitGroup{}
for i := 1; i <= 3; i++ {
    wg.Add(1)
    go func() {
        fmt.Println("处理耗时2秒的任务")
        time.Sleep(time.Second * 2)
        fmt.Println("处理一个任务")
        wg.Done()
    }()
}
fmt.Println("等待所有结果返回")

wg.Wait()
fmt.Println("处理完成啦")

执行结果:

go run .\main.go
处理耗时2秒的任务
处理耗时2秒的任务
处理耗时2秒的任务
等待所有结果返回
处理一个任务
处理一个任务
处理一个任务
处理完成啦

题干实现思路:

缓冲区的管道用户限制最高并发数,而sync.WaitGroup用于等待所有任务处理完毕。

import (
	"sync"
)
type Task int

func Handle(tasks []Task, excute func(task Task)) {
	wg := sync.WaitGroup{}
	ch := make(chan struct{}, 10)
	for i := range tasks {
        // 每执行一个任务,向管道中传入一个值,表示有个任务。如果满了则阻塞
		ch <- struct{}{}
		wg.Add(1)
		task := tasks[i]
		go func() {
			defer wg.Done()
			excute(task)
            // 任务处理完,向管道中取出一个值,表示处理完一个
			<-ch
		}()
	}
	wg.Wait()

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jayLog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值