先来唠唠
实习经历对于即将参加校招的学生来说至关重要。
那些在知名科技公司实习过的学生,往往在校招招聘中更容易获得青睐,有时甚至可以直接获得正式职位,免去了激烈的校招竞争。
实习不仅仅是简历上的一笔,它代表着你已经掌握了基本的技术开发能力,比如数据库设计、操作,以及HTTP请求和JSON响应处理等。此外,实习还能让你熟悉Linux环境和Git协作,甚至可能积累处理线上问题的经验,比如接口性能问题、数据库查询优化、系统资源管理等。
在面试中,如果你能够详细阐述这些问题的背景、定位和解决过程,将极大地提升你的竞争力。企业通常更看重实际操作能力,而非仅仅理论知识。
实习经验能够让企业相信你能够迅速适应工作并带来贡献。作为雇主,自然更愿意招聘能够立即投入工作的人,这样可以缩短新员工的培养周期。
记住,早起的鸟儿有虫吃,不要等到校招才开始准备面试。
下面就是我为你们整理的字节面试真题。
字节一面(技术)
1. make和new的区别?
答案:
new(T)
:- 用于为类型
T
分配内存,并返回指向该内存的指针(*T
)。 - 分配的内存会被初始化为类型
T
的零值。 - 适用于所有类型(如基本类型、结构体、数组等)。
- 示例:
p := new(int)
,p
的类型是*int
,值为0
。
- 用于为类型
make(T, args...)
:- 仅用于初始化内建的引用类型(
slice
、map
、channel
)。 - 返回的是已初始化的类型
T
的值(而非指针)。 - 对于
slice
、map
和channel
,make
会初始化底层数据结构(如分配数组、哈希表等)。 - 示例:
s := make([]int, 10)
,直接返回初始化后的slice
。
- 仅用于初始化内建的引用类型(
关键区别:
new
返回指针,make
返回初始化后的值。make
仅用于slice
、map
、channel
,且需要额外参数(如长度、容量)。
2. mutex锁有几种模式?
答案:
Go的sync.Mutex
有两种模式:
正常模式(Normal Mode):
- 新请求锁的
goroutine
会先尝试直接获取锁。 - 若锁已被占用,则进入一个FIFO队列等待。
- 当锁释放时,队头的
goroutine
会被唤醒,但需要与新到达的goroutine
竞争锁(新到达的可能更易获取锁,因为它们已在CPU上运行)。
- 新请求锁的
饥饿模式(Starvation Mode):
- 当某个
goroutine
等待锁超过1ms
时,触发饥饿模式。 - 锁的所有权会直接移交给队头的
goroutine
,新到达的goroutine
不再竞争,而是直接进入队列尾部。 - 当队列中最后一个
goroutine
获取锁,或等待时间小于1ms
时,切换回正常模式。
- 当某个
目的:避免长时间等待的goroutine
因竞争不过新到达的goroutine
而“饿死”。
3. 讲一下GMP调度模型
答案:
- G(Goroutine):轻量级线程,由Go运行时管理。
- M(Machine):操作系统线程(内核线程),由操作系统调度。
- P(Processor):逻辑处理器,关联本地
G
队列,数量由GOMAXPROCS
决定(默认等于CPU核心数)。
调度流程:
- 每个
P
维护一个本地G
队列(Local Queue),全局G
队列(Global Queue)用于跨P
调度。 M
必须绑定P
才能执行G
。- 当
P
的本地队列为空时,会从全局队列或其他P
的队列“偷”G
(Work Stealing)。 - 若
G
执行阻塞操作(如系统调用),M
会被阻塞,此时P
会解绑并与空闲M
(或新建M
)绑定,继续执行其他G
。 - 阻塞操作完成后,
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()
}
思路:
- 通过缓冲大小为10的
channel
(sem
)控制并发数。 - 每个
goroutine
启动前向sem
发送信号,若缓冲满则阻塞。 goroutine
结束时从sem
取出信号,释放位置。
7. 知道哪些设计模式?
常见设计模式:
- 单例模式:确保类只有一个实例(Go中用
sync.Once
实现)。 - 工厂模式:通过工厂函数创建对象,隐藏实现细节。
- 观察者模式:对象状态变化时通知依赖它的对象(如事件驱动)。
- 装饰器模式:通过组合扩展对象功能(如
io.Reader
包装)。 - 适配器模式:转换接口兼容性(如将第三方接口适配为系统接口)。
- 策略模式:通过接口实现不同算法(如排序策略)。
- 生产者-消费者模式:通过
channel
和goroutine
解耦生产与消费。
Go特有模式:
- 函数选项模式:通过可变参数配置对象(如
NewServer(options...)
)。 - 管道模式:通过
channel
串联多个处理阶段。 - 组合替代继承:通过结构体嵌套复用代码。
字节二面(技术+人事)
有些开放性的问题,就不给出详细答案了,你可以尝试着自己回答一下。
技术面试
- 讲一下一个系统访问的整个链路过程
- K8s有哪些组件?
kube-apiserver、etcd、kube-scheduler、kube-controller-manager、cloud-controller-manager、kubelet、kube-proxy、cAdvisor、Container Runtime、CoreDNS
- 怎么把node里的pod暴露给外面使用?
- 对监控的理解,怎么判断一个系统是否已经挂调了?
- 如果让你对系统进行一个巡检,你会怎么做?
- 举例数据库巡检
- 用过云产品吗?讲一下你对公有云的理解
- 用过OPEN AI吗?你一般怎么使用?
人事面试:
- 从技术上和工作上上一家公司对你有什么成长?
- 在工作中和技术上学到哪些技能?举例说明
- 离职原因,未来职业规划
欢迎关注 ❤
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:sf面试群。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。