😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go小考
    • Go实战
    • 精品课
  • Go宝典

    • 在线宝典
    • B站精选
    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
  • Go下载

    • 视频资源
    • 文档资源
Go求职
  • 求职服务

    • 内推互助
    • 求职助力
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
Go友会
  • 城市
  • 校园
推广返利 🤑
实验区
  • Go周边
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • Go真实面试题汇总系列

    • Go基础篇
  • 宝典内容

    • 20. 2个协程交替打印字母和数字
    • 21. goroutine与线程的区别?
    • 27. 为什么不要大量使用goroutine
    • 38. 协程goroutine
    • 41. go 中用 for 遍历多次执行 goroutine会存在什么问题
    • 49. 问等待所有goroutine结束,怎么做?
    • 56. goroutine 为什么轻量
    • 86. 用Channel和两个协程实现数组相加
    • 98. go协程的实现方式
    • 106. 并行goroutine如何实现
    • 109. goroutine和线程的区别,为什么说goroutine轻量
    • 117. 父 goroutine 退出,如何使得子 goroutine 也退出?
    • 125. 主协程如何等待其余协程完再操作
    • 141. 为什么不要频繁创建和停止goroutine
    • 146. 如何拿到多个goroutine的返回值,如何区别他们
    • 151.golang goroutine的工作原理以及他们怎么进行数据交互的
    • 157. 一个线程打印奇数一个线程打印偶数 交替打印
    • 160. channel主要做什么事情
    • 167. golang 协程机制
    • 168. 协程的栈空间大小有限制吗?会主动扩展吗?
    • 169. 用go实现一个协程池,大概用什么实现
    • 170. go里面为什么需要多协程?
    • 171. goroutine为什么会存在,为什么不使用线程?
    • 173. go协程线程进程区别
    • 176. go协程相比其它协程库区别在哪?
    • 184. 编程go协程交叉顺序打印数组
    • 185. go协程通信
    • 203. 一个goroutine sleep了,操作系统是怎么唤醒的
    • 222. Go的协程可以不可以自己让出cpu
    • 223. Go的协程可以只挂在一个线程上面吗
    • 239. 用go撸一个生产者消费型,用channel通信,怎么友好的关闭chan?
    • 240. goroutine调度源码
    • 248. go实现协程池
    • 249. 两个协程交替打印1到20
    • 251. goroutine 和 kernel thread 之间是什么关系?
    • 254. 用过go,那么进程,协程,线程各自的优缺点
    • 264. Go的多线程
    • 268. 进程和协程
    • 269. 如何解决孤儿进程的出现
    • 274. goroutine为什么比线程开销小,实现原理
    • 277. 协程实现顺序打印123
    • 286. goroutine的调度是出现在什么情况下,调度时做了什么
    • 297. golang有什么提高性能的设计, 重点说说goroutine
    • 298. 进程、线程和协程和通信方式
    • 300. Goroutine 数量是越多越好吗?
    • 308. go协程的简单用法
    • 314. 为什么用户级别的线程 goroutine 比操作系统线程更轻量级?
    • 341. 协程怎么停顿?
    • 367. go 如何关闭goroutine
    • 373. Go 语言协程怎么跑的
    • 375. Go创建协程的过程
    • 376. 协程共享哪些资源?
    • 385. go中协程是如何实现的
    • 386. 协程中参数直接使用,和传参的区别是什么,为什么会造成这种结果
    • 389. 是否写过go语言多协程内容
    • 394. 开俩个协程,一个协程生产数据,另一个协程对数据进行处理,处理完后再把数据发回去,使用管道如何实现?
    • 406. goroutine泄露
    • 407. 如何停止一个goroutine
    • 410. 查看goroutine (579)
    • 420. 用go协程的时候也是要走IO的,go是如何处理的?
    • 444. 有没有了解过goroutine的底层数据结构, 为什么协程比线程轻量且快
    • 461. 如何限制 goroutine 并发数量 (channel 或 WaitGroup)
    • 465. Go里面一个协程能保证绑定在一个内核线程上面的。

😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

461. 如何限制 goroutine 并发数量 (channel 或 WaitGroup)


企业题库解析小组

题目序号:6744 题目来源:360 频次:6

答案:苏木

限制 goroutine 并发数量有两种办法:

  • 使用channel通道
  • WaitGroup

chanel 实现 goroutine 并发数量限制
在每次执行 go 语句之前向通道写入值,直到通道满之后就阻塞了,从而实现对 goroutine 数量限制。

func elegance(){
    v := <-ch
    fmt.Println("the ch value receive",v)
}

func main(){
    ch = make(chan int,5)
    for i:=0;i<10;i++{
        ch <- i
        fmt.Println("the ch value send",ch)
        go elegance()
        fmt.Println("the result i",i)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

但尽管这样还是会有新的问题出现:因为在所有 goroutine 执行完成之前, main 函数可能就退出了,导致一些 goroutine 被强制结束。

这时候我们就需要使用 sync.WaitGroup,来实现对 goroutine 的结束过程可控。

WaitGroup 实现 goroutine 并发数量限制

WatiGroup是sync包中的一个struct类型,用来收集需要等待执行完成的goroutine。下面是它的定义:

type WaitGroup struct {
        // Has unexported fields.
}
    A WaitGroup waits for a collection of goroutines to finish. The main
    goroutine calls Add to set the number of goroutines to wait for. Then each
    of the goroutines runs and calls Done when finished. At the same time, Wait
    can be used to block until all goroutines have finished.

    A WaitGroup must not be copied after first use.


func (wg *WaitGroup) Add(delta int)
func (wg *WaitGroup) Done()
func (wg *WaitGroup) Wait()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

它有3个方法:

  • Add():每次激活想要被等待完成的goroutine之前,先调用Add(),用来设置或添加要等待完成的goroutine数量。 例如Add(2)或者两次调用Add(1)都会设置等待计数器的值为2,表示要等待2个goroutine完成
  • Done():每次需要等待的goroutine在真正完成之前,应该调用该方法来人为表示goroutine完成了,该方法会对等待计数器减1
  • Wait():在等待计数器减为0之前,Wait()会一直阻塞当前的goroutine

也就是说,Add()用来增加要等待的goroutine的数量,Done()用来表示goroutine已经完成了,减少一次计数器,Wait()用来等待所有需要等待的goroutine完成。

通过实例可以很容易理解。

package main

import (  
    "fmt"
    "sync"
    "time"
)

func process(i int, wg *sync.WaitGroup) {  
    fmt.Println("started Goroutine ", i)
    time.Sleep(2 * time.Second)
    fmt.Printf("Goroutine %d ended\n", i)
    wg.Done()
}

func main() {  
    no := 3
    var wg sync.WaitGroup
    for i := 0; i < no; i++ {
        wg.Add(1)
        go process(i, &wg)
    }
    wg.Wait()
    fmt.Println("All go routines finished executing")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

上面激活了3个 goroutine,每次激活 goroutine 之前,都先调用 Add() 方法增加一个需要等待的 goroutine 计数。每个 goroutine 都运行 process() 函数,这个函数在执行完成时需要调用 Done() 方法来表示 goroutine 的结束。激活3个 goroutine 后, main goroutine 会执行到 Wait(),由于每个激活的 goroutine 运行的 process() 都需要睡眠2秒,所以 main goroutine 在 Wait() 这里会阻塞一段时间(大约2秒),当所有 goroutine 都完成后,等待计数器减为0,Wait() 将不再阻塞,于是 main goroutine 得以执行后面的 Println()。

还有一点需要特别注意的是 process() 中使用指针类型的 *sync.WaitGroup 作为参数,才能使3个 goroutine 共享一个 wg。

参考资料

通过 channel 限制 goroutine 并发数量 https://blog.csdn.net/weixin_42445362/article/details/124607185

WaitGroup 用法说明 https://www.cnblogs.com/f-ck-need-u/p/10004787.html