concurrence.md

·interview-questions

并发相关

讲一下 channel,以及无缓冲 channel 和 有缓冲 channel 有什么区别

A:channel 是 Go 语言中用于 goroutine 之间通信和同步的机制,类似于管道,可以在不同的 goroutine 之间传递数据,它替代了共享内存,通过通信来共享内存,让并发更安全更容易理解;无缓冲 channel 是指在发送数据时,发送方和接收方必须同时存在,才能完成数据的传递;而有缓冲 channel 则允许在发送数据时不需要接收方同时存在,发送方可以先将数据放入缓冲区中,接收方可以稍后再来接收数据;无缓冲 channel 更加严格,但也更容易出现死锁,而有缓冲 channel 则更加灵活,但也可能导致数据丢失或不一致的问题;在实际开发中,比如我有一个日志模块收集 goroutine,如果用无缓冲 channel,那么每条日志都要等后端写库确认后发送才能继续,会严重拖慢主流程,如果用有缓冲 channel,主流程只需要把日志推送缓冲就可以马上返回,大部分日志写入都在后台异步完成,保证了不会丢日志的同时也提高了并发吞吐量

Go 语言中的 Channel 是什么, 有哪些用途,如何处理阻塞?

map 是并发安全的吗,如何实现并发安全

A:Go 自身内置的 map 并不是并发安全的,多个 goroutine 如果同时写会触发 panic,如果想要用并发安全的 map,可以使用标准库的 sync.map,或者自己用 sync 的互斥锁读写锁写一套并发安全的 map,或者还有一些第三方的并发 map 库也可以用

Q:讲讲 GMP 模型调度器

A:GMP 是 go 语言中实现 M 比 N 调度的模型,G 是指 goroutine,M 是指 machine,也就是真正的操作系统线程,P 是指 processor,是运行时的调度令牌,数量由 GOMAXPROCS 这个参数控制;每个 P 会管理一个本地就绪队列,空闲的 M 拿到 P 之后就会去执行队列里的 G,当本地队列空了 P 就会从全局队列或其他 P 的队列窃取 G,go 语言通过写屏障还实现了抢占,确保长时间运行的 G 会释放 P,让其他的 G 也有机会跑,在系统调用时 M 会临时脱离 P 去调用内核,运行时再为 P 分配新的 M,让 go 代码不被阻塞,整个模型既保证了高并发,又能充分利用多核,非常适合网络和 IO 密集场景

go 语言中的线程池参数和怎么配置线程数

A:go 语言里其实没有显式的线程池概念,go 主要是用 GMP 实现的高并发,然后使用 GOMAXPROCS 这个参数来控制操作系统的线程数,默认值是机器的 CPU 核心数,如果想要控制任务并发度,可以在 goroutine 之上自己实现一个 worker pool,用一个缓冲 channel 作为信号量,或用一些比较成熟的第三方库,来限制同时启用的 goroutine 数量

如果让你设计 go 里面的锁,应该怎么设计

A:嗯我会仿照 sync.Mutex 设计一个轻量级、原子性强且调度友好的结构,我会用一个原子整型表示锁状态,先用 CAS 尝试加锁,失败就把 goroutine 放入等待队列并 park,解锁时再把锁状态清零,唤醒队列中下一个 goroutine;我也会加入短时间自选、队列唤醒顺序控制,以及调试时的死锁检测功能,因为 goroutine 是由运行时调度的,不能用操作系统级的锁做阻塞,所以锁必须尽可能用户态完成调度,减少内核切换

go 语言的并发模型是什么?

go 的运行时是什么?

如何控制 go routine 的生命周期?

Go什么时候发生阻塞?阻塞时调度器会怎么做?

切片是并发安全的吗?

go 语言中协程间通信或数据交互一般会用什么数据结构?可以用 map 吗?

  • 你有提到 go 语言中的多线程高并发的应用,那你主要的应用场景是什么,达到了什么样的目标呢

  • 那假如现在有一个协程异步执行了一个任务,他这个任务可能在协程的逻辑中抛出 panic,那这时候你会如何处理这个 panic

  • 那比如说我们在协程的代码逻辑里面发生了 panic 之后,有可能会导致我们的系统崩溃,那我该在哪个层面,比如是在协程的内侧,还是协程的外侧,如何去防止我们的系统因为产生了这个 panic 而崩溃呢

  • 那假如说我这个协程在执行完之后我的主进程已经停止了,就是已经执行完毕了,那这个时候你如何去 catch 这个协程里面的异常呢,你是通过什么方式,比如像用什么关键字

  • 那你还有什么更好的方法吗,比如我在程序层避免它崩掉

  • 假设现在有一个函数,它内部写了一个子协程,子 goroutine,这个 goroutine 内部 panic 掉了,那你觉得外层的程序它能捕捉到内层的 panic 吗?

  • 你刚刚有提到 goroutine,解释一下进程、线程和协程?为什么协程会出现,它的应用场景是什么?

  • 那为什么会引入到协程呢?它是为了解决什么样的问题呢?

  • 那你在哪一些场景下会更倾向于使用协程?除了所谓的 context 切换,因为这个问题在进程线程里都有,那你拿到一个任务,在什么场景下你会更愿意用协程来解决这个任务?(答了小任务,举例查表,面试官提醒说这个查表的过程其实就是一个 I/O 的过程)

  • 那像 go 里面协程间通信或者数据交互的话我们一般用些什么结构?用 map 可以吗?