Go面试看这里了~(二十一)

161 篇文章 12 订阅

原文地址:Go面试看这里了~(二十一)

1、sync.Map的实现原理?

先看下src/sync/map.go文件中几个相关结构体的数据结构:

type Map struct {
    // 当涉及到脏数据(dirty)操作时候,需要使用这个锁
    mu Mutex
    
    // read是一个只读数据结构,包含一个map结构,
    // 读不需要加锁,只需要通过 atomic 加载最新的值即可
    read atomic.Value // readOnly
    
    // dirty 包含部分map的键值对,如果操作需要mutex获取锁
    // 最后dirty中的元素会被全部提升到read里的map去
    dirty map[interface{}]*entry
    
    // misses是一个计数器,用于记录read中没有的数据而在dirty中有的数据的数量。
    // 也就是说如果read不包含这个数据,会从dirty中读取,并misses+1
    // 当misses的数量等于dirty的长度,就会将dirty中的数据迁移到read中
    misses int
}

sync.Map的原理是通过分离读写map和原子指令来实现读的近似无锁,并通过延迟更新的方式来保证读的无锁化,其主要思想就是读写分离,空间换时间。

sync.Map的优点:

  1. 空间换时间:通过冗余的两个数据结构(read、dirty),实现加锁对性能的影响。

  2. 使用只读数据(read),避免读写冲突。

  3. 动态调整:miss次数多了之后,将dirty数据迁移到read中。

  4. double-checking。

  5. 延迟删除,删除一个键值只打标记,在迁移dirty数据时才清理删除的数据。

  6. 优先从read读取、更新、删除,因为对read的读取不需要锁。

2、可以限制运行时操作系统线程的数量吗?

可用环境变量GOMAXPROCS或runtime.GOMAXPROCS(num int)设置,GOMAXPROCS限制的是同时执行用户态Go代码的操作系统线程的数量,但是对于被系统调用阻塞的线程数量是没有限制的,GOMAXPROCS的默认值等于CPU的逻辑核数,同一时间,一个核只能绑定一个线程,然后运行被调度的goroutine,因此对于CPU密集型的任务,若该值过大,例如设置为CPU逻辑核数的2倍,会增加线程切换的开销,降低性能,对于I/O密集型应用,适当地调大该值,可以提高I/O吞吐率。

3、协程泄露(Goroutine Leak)?

Go并发是以goroutine和channel的形式实现,协程泄露指的是goroutine创建后长时间得不到释放,且还在不断创建新goroutine,最终导致内存耗尽,程序崩溃。

常见导致协程泄露的场景如下

  1. 缺少接收器,导致发送阻塞:启动N个协程接收channel中信息,但channel并不会发送那么多信息,从而导致接收协程阻塞,不能退出。

  2. 死锁(dead lock):同一个goroutine中使用同一个chnnel读写,其次是2个以上的Go程中使用同一个channel通信,且读写channel先于Go程序创建,再次就是channel和读写锁、互斥锁混用。

  3. 无限死循环(infinite loops):I/O 操作上的堵塞也可能造成泄露,例如发送请求到 API 服务器,而没有使用超时;或者程序单纯地陷入死循环中。

至此,本次分享就结束了,后期会慢慢补充。

以上仅为个人观点,不一定准确,能帮到各位那是最好的。

好啦,到这里本文就结束了,喜欢的话就来个三连击吧。

扫码关注公众号,获取更多优质内容。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

luyaran

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

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

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

打赏作者

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

抵扣说明:

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

余额充值