【Golang 面试 - 进阶题】每日 3 题(九)

✍个人博客:Pandaconda-CSDN博客

📣专栏地址:http://t.csdnimg.cn/UWz06

📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~

❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

25. G o goroutine 和线程的区别?

Go 的 goroutine 是一种轻量级的协程,与传统的操作系统线程相比,具有以下区别:

1、调度模型

Go 语言中的 goroutine 采用的是 M:N 调度模型,即 M 个 goroutine(协程)映射到 N 个系统线程上,这些线程由 Go 运行时进行调度。而传统的线程则是采用的 1:1 调度模型,即一个线程对应一个系统线程。

2、轻量级

Go 的 goroutine 比传统的线程更加轻量级,创建和销毁 goroutine 的代价比较小,且 goroutine 的初始栈大小只有几 KB,而线程的栈大小通常要大得多。

3、内存占用

由于 goroutine 的内存占用比线程更小,因此在同样的硬件资源下,Go 程序可以运行更多的 goroutine。

4、通信机制

在 Go 中,goroutine 之间的通信使用的是 Channel,Channel 可以避免传统线程中使用锁带来的复杂性和性能损失。

5、错误处理

在传统线程中,如果一个线程抛出异常或崩溃,那么整个进程都会被杀死。而在 Go 中,当一个 goroutine 抛出 panic 时,只有该 goroutine 会被终止,不会影响其他 goroutine 和整个进程。

综上所述,与传统的线程相比,Go 的 goroutine 更加轻量级,占用资源更少,拥有更好的并发性能和更容易处理错误。这也是 Go 语言在并发编程中的优势所在。

26. G o 如何查看正在执行的 goroutine 数量?

程序中引入 pprof pakage

在程序中引入 pprof package:

Go 复制代码
import _ "net/http/pprof"

程序中开启 HTTP 监听服务:

Go 复制代码
package main
import (
    "net/http"
    _ "net/http/pprof"
)
func main() {
    for i := 0; i < 100; i++ {
        go func() {
            select {}
        }()
    }
    go func() {
        http.ListenAndServe("localhost:6060", nil)
    }()
    select {}
}

分析 goroutine 文件

在命令行下执行:

Go 复制代码
go tool pprof -http=:1248 http://127.0.0.1:6060/debug/pprof/goroutine

会自动打开浏览器页面如下图所示:

在图中可以清晰的看到 goroutine 的数量以及调用关系,可以看到有 103 个 goroutine。

27. G o 如何控制并发的 goroutine 数量?

为什么要控制 goroutine 并发的数量?

在开发过程中,如果不对 goroutine 加以控制而进行滥用的话,可能会导致服务整体崩溃。比如耗尽系统资源导致程序崩溃,或者 CPU 使用率过高导致系统忙不过来。

用什么方法控制 goroutine 并发的数量?

1. 有缓冲 channel

利用缓冲满时发送阻塞的特性。

Go 复制代码
package main
import (
    "fmt"
    "runtime"
    "time"
)
var wg = sync.WaitGroup{}
func main() {
    // 模拟用户请求数量
    requestCount := 10
    fmt.Println("goroutine_num", runtime.NumGoroutine())
    // 管道长度即最大并发数
    ch := make(chan bool, 3)
    for i := 0; i < requestCount; i++ {
        wg.Add(1)
        ch <- true
        go Read(ch, i)
    }
     wg.Wait()
}
func Read(ch chan bool, i int) {
    fmt.Printf("goroutine_num: %d, go func: %d", runtime.NumGoroutine(), i)
    <-ch
    wg.Done()
}

输出结果:默认最多不超过 3(4-1)个 goroutine 并发执行。

html 复制代码
goroutine_num 1
goroutine_num: 4, go func: 1
goroutine_num: 4, go func: 3
goroutine_num: 4, go func: 2
goroutine_num: 4, go func: 0
goroutine_num: 4, go func: 4
goroutine_num: 4, go func: 5
goroutine_num: 4, go func: 6
goroutine_num: 4, go func: 8
goroutine_num: 4, go func: 9
goroutine_num: 4, go func: 7

2. 无 缓冲 channel

任务发送和执行分离,指定消费者并发协程数。

Go 复制代码
package main
import (
    "fmt"
    "runtime"
    "sync"
)
var wg = sync.WaitGroup{}
func main() {
    // 模拟用户请求数量
    requestCount := 10
    fmt.Println("goroutine_num", runtime.NumGoroutine())
    ch := make(chan bool)
    for i := 0; i < 3; i++ {
        go Read(ch, i)
    }
    for i := 0; i < requestCount; i++ {
        wg.Add(1)
        ch <- true
    }
    wg.Wait()
}
func Read(ch chan bool, i int) {
    for _ = range ch {
        fmt.Printf("goroutine_num: %d, go func: %d", runtime.NumGoroutine(), i)
        wg.Done()
    }
}
相关推荐
艾莉丝努力练剑2 小时前
【LeetCode&数据结构】单链表的应用——反转链表问题、链表的中间节点问题详解
c语言·开发语言·数据结构·学习·算法·leetcode·链表
武子康3 小时前
Java-72 深入浅出 RPC Dubbo 上手 生产者模块详解
java·spring boot·分布式·后端·rpc·dubbo·nio
椰椰椰耶4 小时前
【Spring】拦截器详解
java·后端·spring
没有bug.的程序员5 小时前
JAVA面试宝典 - 《MyBatis 进阶:插件开发与二级缓存》
java·面试·mybatis
brzhang5 小时前
我操,终于有人把 AI 大佬们 PUA 程序员的套路给讲明白了!
前端·后端·架构
倔强青铜36 小时前
苦练Python第18天:Python异常处理锦囊
开发语言·python
u_topian6 小时前
【个人笔记】Qt使用的一些易错问题
开发语言·笔记·qt
珊瑚里的鱼7 小时前
LeetCode 692题解 | 前K个高频单词
开发语言·c++·算法·leetcode·职场和发展·学习方法
AI+程序员在路上7 小时前
QTextCodec的功能及其在Qt5及Qt6中的演变
开发语言·c++·qt