GoLang Interview Questions

  sonic0002        2024-05-25 03:08:18       900        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

以下列出了一些常见的 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


  0 COMMENT


No comment for this article.



  RANDOM FUN

Select all squares with bugs