头图

先来唠唠

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

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

实习不仅仅是简历上的一笔,它代表着你已经掌握了基本的技术开发能力,比如数据库设计、操作,以及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)

    • 新请求锁的goroutine会先尝试直接获取锁。
    • 若锁已被占用,则进入一个FIFO队列等待。
    • 当锁释放时,队头的goroutine会被唤醒,但需要与新到达的goroutine竞争锁(新到达的可能更易获取锁,因为它们已在CPU上运行)。
  2. 饥饿模式(Starvation Mode)

    • 当某个goroutine等待锁超过1ms时,触发饥饿模式。
    • 锁的所有权会直接移交给队头的goroutine,新到达的goroutine不再竞争,而是直接进入队列尾部。
    • 当队列中最后一个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,备注:sf面试群。


王中阳讲编程
822 声望305 粉丝