GoLang Interview Questions

English 简体中文 繁体中文 ภาษาไทย Tiếng Việt
Summary

Go's concurrency model, GMP, efficiently schedules goroutines with minimal stack sizes, featuring mechanisms like goroutine stealing and graceful handling of IO blocks. Its garbage collection process involves STW phases for setup and termination, alongside a concurrent marking phase that utilizes write barriers and Mark Assist for performance. Key language features include slices, which are dynamic views over arrays, and the panic, defer, recover triad for robust error management and cleanup, with recover specifically effective within deferred functions. Developers leverage the Context interface for goroutine control and value propagation, while channels provide safe communication, though improper use can cause goroutine leaks. Understanding the differences between new() and make(), pointer versus non-pointer method receivers, and implicit interface implementation checks are also crucial for effective Go development.

以下列出了一些常见的 GoLang 面试问题以及基于作者经验的相应答案。该列表会经常更新新的理解。敬请关注。

GoLang 的 GMP 模型是什么?

GoLang 使用 goroutine 来实现并发,并且以高并发支持而闻名,因为该语言定义了自己的 goroutine 调度和处理系统,该系统被称为 GMP 模型。

它的工作原理是,M 通常被定义为正在产生的 OS 线程(然后每个 M 线程都应该与一个 Process 队列相关联,并且每个 Process 队列可以有多个 goroutine。Process 队列的数量由 GOMAXPROCS() 定义。当 M 处理完与其关联的 P 中的所有 G 时,它会从其他 M 窃取 G,也会从全局 P 队列中窃取。

如果 M 由于 IO 阻塞或网络阻塞而挂起,它会从其 P 中分离出来,并且此 P 将与另一个可用的 M 相关联,如果不存在,则会创建一个新的 M。

如果 goroutine 无法放入本地 P 中,它将被放入全局 P 队列中。如果 M 无法从其他 M 窃取 G,它将从全局 P 队列中获取。

每个 goroutine 只有 2K 的堆栈大小,这非常小,这就是 GoLang 支持更多并发的原因。并且这种 goroutine 执行之间的切换是基于用户线程空间的,因此切换上下文的成本与线程或进程相比并不高

GoLang 中的 GC 机制是什么?

有三个阶段:Mark Setup(标记设置)、Mark(标记)和 Mark Termination(标记终止)。Mark Setup 和 Mark Termination 是 STW(Stop The World)。Mark 阶段是并发的。

在进行 Mark Setup 时,将启用 Write Barrier(写屏障)以确保数据完整性,然后它将等待所有正在运行的 goroutine 停止。 

当 Marking 开始时,它将占用 25% 的 CPU,并为自己分配一个 P 来进行垃圾回收。标记阶段将标记仍在使用的头部,它会尝试查看所有 goroutine 的堆栈并遍历其根指针,然后从根遍历并进行标记。如果标记无法及时完成,它将进行 Mark Assist(标记辅助),这意味着要求其他应用程序 goroutine 帮忙。以加速标记。

在进行 Mark Termination 时,Write Barrier 将被关闭,并且将完成清理工作。

何时开始进行 GC?

  • GC Percentage(GC 百分比),即与先前 GC 周期中使用的内存相比,要分配的新内存的百分比。
  • 通过调用 runtime.GC() 手动触发

Slice 的底层工作原理是什么?

Slice 描述的是数组的一部分,它与数组不同。

Slice 头部具有长度、容量和零元素指针。底层由数组支持。如果达到容量,则无法再增长,需要重新创建底层数组并重新分配。如果未达到容量,则可以在需要时增长。

Panic、defer 和 recover

对于 defer,它是如何以 FILO(先进后出)方式工作的

  1. 延迟函数的参数在评估 defer 语句时进行评估。

  2. 延迟函数调用在周围函数返回后以先进后出的顺序执行

  3. 延迟函数可以读取和赋值给返回函数的命名返回值。

Panic 将返回执行,并且函数中的 defers 将继续执行。 

Recover 仅在延迟函数内部有用。在普通函数中,recover 没有效果,什么也不做。

Defer recover 仅适用于当前 goroutine,它不适用于其衍生的 goroutine。

Context,它非常强大

Context 接口中的 4 个函数: 

  • Deadline(),
  • Done(),
  • Err(),
  • Value(key interface{})

这样做的好处是资源共享、goroutine 控制

有一些派生的 goroutine,例如 WithCancel、WithDeadline、WithTimeout、WithValue

WithCancel: 

  1. Cancel 函数将级联到子上下文

  2. 创建新的子上下文时,它将在父上下文中注册。 

WithValue

  1. 该键必须是可比较的,因为在调用 Value() 函数时会进行 c.key == key 检查

  2. slice、map 和 function 不可比较。主要是因为 slice 不可比较,因为它是一种引用类型,仅比较地址没有意义,并且由于 len/cap 特性,比较 slice 中的内容会增加复杂性

Channel

Channel 是一种通过通信共享内存的方式

有缓冲和非缓冲 channel

  • 关闭 nil 或已关闭的 channel 会 panic
  • 向 nil channel 发送值会永远阻塞,关闭的 channel 会 panic
  • 从 nil channel 接收数据会永远阻塞,关闭的 channel 会立即返回

何时会发生 goroutine 泄漏?

一些场景包括:

  1. 当 channel 未关闭,而 goroutine 一直在等待从 channel 接收数据时
  2. 当某些资源未正确关闭,而某些 goroutine 仍在等待来自另一端的响应,并且没有为阻塞 IO 设置足够的超时时间时

new() 和 make() 之间有什么区别?

new() 只会分配内存,而 make() 会初始化数据

使用 new() 创建的对象已准备好使用,但需要在需要时显式初始化其属性才能使用

make() 只能用于 slice、map 和 channel 类型。

详细的区别可以在这里找到。

指针和非指针方法接收器之间的区别?

就像函数调用中的按引用传递按值传递一样。

如果要改变 struct,或者 struct 对于接收器来说太大,可以选择定义指针方法接收器。

如果某些函数具有指针接收器,则其余函数也应该具有指针接收器,以保持一致性。

如何检查 struct 是否实现了接口?

GoLang 中没有像 Java 等其他语言那样的 implements 关键字。如果 struct 实现了接口的所有方法,则认为它实现了该接口。如果 struct 代码与接口定义不在同一位置,则可能难以找出 struct 是否实现了特定接口。在某些情况下,这可能会导致运行时问题。

有几种方法可以检查:

  • 使用虚拟对象进行类型断言。 var _ = (SomeStruct{}).(SomeInterface)
  • 使用反射。 reflect.TypeOf(OneInterface).Implements(reflect.TypeOf(SomeInterface).Elem())

有关其他方法,请访问这里

MEMORY CONCURRENCY INTERVIEW QUESTION GOLANG

  RELATED

  COMMENTS

0

No comment for this article.