写点什么

第一次面字节,一面很简单,二面被疯狂拷打!

作者:王中阳Go
  • 2025-02-11
    湖南
  • 本文字数:2536 字

    阅读完需:约 8 分钟

先来唠唠

实习经历对于即将参加校招的学生来说至关重要。


那些在知名科技公司实习过的学生,往往在校招招聘中更容易获得青睐,有时甚至可以直接获得正式职位,免去了激烈的校招竞争。


实习不仅仅是简历上的一笔,它代表着你已经掌握了基本的技术开发能力,比如数据库设计、操作,以及 HTTP 请求和 JSON 响应处理等。此外,实习还能让你熟悉 Linux 环境和 Git 协作,甚至可能积累处理线上问题的经验,比如接口性能问题、数据库查询优化、系统资源管理等。


在面试中,如果你能够详细阐述这些问题的背景、定位和解决过程,将极大地提升你的竞争力。企业通常更看重实际操作能力,而非仅仅理论知识。


实习经验能够让企业相信你能够迅速适应工作并带来贡献。作为雇主,自然更愿意招聘能够立即投入工作的人,这样可以缩短新员工的培养周期。


记住,早起的鸟儿有虫吃,不要等到校招才开始准备面试。


下面就是我为你们整理的字节面试真题

字节一面(技术)

1. make 和 new 的区别?

答案:


  • new(T)

  • 用于为类型T分配内存,并返回指向该内存的指针(*T)。

  • 分配的内存会被初始化为类型T的零值。

  • 适用于所有类型(如基本类型、结构体、数组等)。

  • 示例:p := new(int)p的类型是*int,值为0

  • make(T, args...)

  • 仅用于初始化内建的引用类型slicemapchannel)。

  • 返回的是已初始化的类型T的值(而非指针)。

  • 对于slicemapchannelmake会初始化底层数据结构(如分配数组、哈希表等)。

  • 示例:s := make([]int, 10),直接返回初始化后的slice


关键区别


  • new返回指针,make返回初始化后的值。

  • make仅用于slicemapchannel,且需要额外参数(如长度、容量)。



2. mutex 锁有几种模式?

答案:Go 的sync.Mutex有两种模式:


  1. 正常模式(Normal Mode)

  2. 新请求锁的goroutine会先尝试直接获取锁。

  3. 若锁已被占用,则进入一个 FIFO 队列等待。

  4. 当锁释放时,队头的goroutine会被唤醒,但需要与新到达的goroutine竞争锁(新到达的可能更易获取锁,因为它们已在 CPU 上运行)。

  5. 饥饿模式(Starvation Mode)

  6. 当某个goroutine等待锁超过1ms时,触发饥饿模式。

  7. 锁的所有权会直接移交给队头的goroutine,新到达的goroutine不再竞争,而是直接进入队列尾部。

  8. 当队列中最后一个goroutine获取锁,或等待时间小于1ms时,切换回正常模式。


目的:避免长时间等待的goroutine因竞争不过新到达的goroutine而“饿死”。



3. 讲一下 GMP 调度模型

答案:


  • G(Goroutine):轻量级线程,由 Go 运行时管理。

  • M(Machine):操作系统线程(内核线程),由操作系统调度。

  • P(Processor):逻辑处理器,关联本地G队列,数量由GOMAXPROCS决定(默认等于 CPU 核心数)。


调度流程


  1. 每个P维护一个本地G队列(Local Queue),全局G队列(Global Queue)用于跨P调度。

  2. M必须绑定P才能执行G

  3. P的本地队列为空时,会从全局队列或其他P的队列“偷”G(Work Stealing)。

  4. G执行阻塞操作(如系统调用),M会被阻塞,此时P会解绑并与空闲M(或新建M)绑定,继续执行其他G

  5. 阻塞操作完成后,G会被重新放入队列,M尝试重新绑定P


优势:减少线程切换开销,提高并发性能。



4. 语法纠错题

循环中延迟关闭资源


for _, file := range files {    f, _ := os.Open(file)    defer f.Close()}
复制代码


错误原因defer在函数返回时执行,循环中多次打开文件可能导致资源耗尽。


修复:在匿名函数中立即执行:


for _, file := range files {    func() {        f, _ := os.Open(file)        defer f.Close() // 每次循环结束后立即关闭    }()}
复制代码



5. 算法:爬楼梯

问题:一次爬 1 或 2 阶,求n阶楼梯的方法数。


答案(动态规划)


func climbStairs(n int) int {    if n <= 2 {        return n    }    a, b := 1, 2    for i := 3; i <= n; i++ {        a, b = b, a+b    }    return b}
复制代码


思路:递推公式dp[i] = dp[i-1] + dp[i-2],优化空间复杂度为O(1)



6. 编程题:控制并发数(有缓冲 channel)

答案


func main() {    var wg sync.WaitGroup    sem := make(chan struct{}, 10) // 缓冲大小为10        for i := 0; i < 100; i++ {        sem <- struct{}{} // 阻塞直到有空位        wg.Add(1)        go func(id int) {            defer func() {                <-sem // 释放位置                wg.Done()            }()            fmt.Printf("Task %d running\n", id)            time.Sleep(time.Second)        }(i)    }    wg.Wait()}
复制代码


思路


  1. 通过缓冲大小为 10 的channelsem)控制并发数。

  2. 每个goroutine启动前向sem发送信号,若缓冲满则阻塞。

  3. goroutine结束时从sem取出信号,释放位置。



7. 知道哪些设计模式?

常见设计模式


  1. 单例模式:确保类只有一个实例(Go 中用sync.Once实现)。

  2. 工厂模式:通过工厂函数创建对象,隐藏实现细节。

  3. 观察者模式:对象状态变化时通知依赖它的对象(如事件驱动)。

  4. 装饰器模式:通过组合扩展对象功能(如io.Reader包装)。

  5. 适配器模式:转换接口兼容性(如将第三方接口适配为系统接口)。

  6. 策略模式:通过接口实现不同算法(如排序策略)。

  7. 生产者-消费者模式:通过channelgoroutine解耦生产与消费。


Go 特有模式


  • 函数选项模式:通过可变参数配置对象(如NewServer(options...))。

  • 管道模式:通过channel串联多个处理阶段。

  • 组合替代继承:通过结构体嵌套复用代码。

字节二面(技术+人事)

有些开放性的问题,就不给出详细答案了,你可以尝试着自己回答一下。

技术面试

  1. 讲一下一个系统访问的整个链路过程

  2. K8s 有哪些组件?


kube-apiserver、etcd、kube-scheduler、kube-controller-manager、cloud-controller-manager、kubelet、kube-proxy、cAdvisor、Container Runtime、CoreDNS


  1. 怎么把 node 里的 pod 暴露给外面使用?

  2. 对监控的理解,怎么判断一个系统是否已经挂调了?

  3. 如果让你对系统进行一个巡检,你会怎么做?

  4. 举例数据库巡检

  5. 用过云产品吗?讲一下你对公有云的理解

  6. 用过 OPEN AI 吗?你一般怎么使用?

人事面试:

  1. 从技术上和工作上上一家公司对你有什么成长?

  2. 在工作中和技术上学到哪些技能?举例说明

  3. 离职原因,未来职业规划

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:infoq 面试群。

发布于: 刚刚阅读数: 4
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
第一次面字节,一面很简单,二面被疯狂拷打!_Go_王中阳Go_InfoQ写作社区