很多朋友在找工作的时候都会遇到各种外包岗,今天分享的面经就是出自组织内部的朋友在百度外包的面试;
看到这个岗位我就有点好奇,如果同时拿到了大厂外包的offer和小公司的offer,你们会怎么选?欢迎大家留言讨论。
面经详解
1. 自我介绍
一定要提前准备好,时间控制在2~3分钟,不要说太多也不要说太少。
2. make的作用
make
是 Go 语言中用于初始化切片(slice)、映射(map)和通道(channel)的内置函数。具体作用如下:
- 切片:分配底层数组并初始化切片结构(长度、容量、指针)。
- 映射:分配哈希表并初始化。
- 通道:创建用于协程间通信的通道。
make
的参数根据类型不同而变化: - 切片:
make([]T, length, capacity)
(容量可选)。 - 映射:
make(map[K]V, initialCapacity)
(初始容量可选)。 - 通道:
make(chan T, bufferSize)
(缓冲区大小可选)。
3. make的容量
容量的含义根据类型不同而不同:
- 切片:容量表示底层数组的总大小,必须 ≥ 长度。例如,
make([]int, 5, 10)
创建一个长度为 5、容量为 10 的切片。 - 通道:容量表示缓冲区大小,即通道在阻塞前可存储的元素数。例如,
make(chan int, 5)
创建一个缓冲区为 5 的通道。 - 映射的容量(
make(map[K]V, capacity)
)表示初始哈希表的空间预分配,但映射的实际容量会动态调整。
4. channel有几种类型
Channel 的类型分为以下三种:
- 双向通道:默认类型,可发送和接收数据,例如
chan int
。 - 只读通道(
<-chan T
):仅能接收数据。 只写通道(
chan<- T
):仅能发送数据。
通过类型转换可实现只读或只写的限制,例如:ch := make(chan int) var readOnly <-chan int = ch // 只读 var writeOnly chan<- int = ch // 只写
5. 实际应用最常用哪种
实际应用中,带缓冲区的双向通道最常见。例如:
- 任务队列:通过缓冲通道实现异步处理,提升吞吐量(如
make(chan Task, 100)
)。 - 流量控制:结合
select
和缓冲区限制并发数。
无缓冲通道多用于同步场景(如信号通知),但带缓冲的通道更灵活且性能更优。
6. 并发编程常用指令
- 协程创建:
go func() { ... }()
。 通道操作:
- 发送数据:
ch <- data
。 - 接收数据:
data := <-ch
。
- 发送数据:
同步工具:
sync.WaitGroup
:等待多个协程完成(Add()
,Done()
,Wait()
)。sync.Mutex
/sync.RWMutex
:保护共享资源。sync.Map
:线程安全的映射。
- 通道选择:
select
处理多通道操作。 - 原子操作:
sync/atomic
包提供原子读写(如atomic.AddInt32()
)。
7. 代码题:并发请求下游并控制 QPS
需求:读取文件中的请求信息,并发请求下游服务,控制每秒请求数(QPS)。
实现示例:
func main() {
limiter := rate.NewLimiter(rate.Every(time.Second), 10) // QPS=10
file, _ := os.Open("requests.txt")
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
req := scanner.Text()
go func(r string) {
ctx := context.Background()
limiter.Wait(ctx) // 等待令牌
callDownstream(r)
}(req)
}
}
func callDownstream(request string) {
// 发送请求逻辑
}
关键点:
- 使用
rate.Limiter
控制 QPS。 - 协程池或带缓冲通道可进一步优化资源管理。
8. 数据库常用用法
8.1 表设计
- 业务拆分:通过逻辑外键关联(如用户表与订单表)。
字段设计:
NOT NULL
约束避免空值。- 合理选择类型(如
INT
vsVARCHAR
)。
- 索引优化:高频查询字段(如用户 ID)添加索引。
- 分库分表:数据量大时按哈希或范围分片。
8.2 并发控制
- 读写分离:主库写,从库读。
- 缓存热点数据:Redis 缓存高频查询结果。
- 流量削峰:Kafka 异步处理请求。
9. 慢查询优化
9.1 SQL 优化
- 精简查询字段:避免
SELECT *
。 - 优化 JOIN:避免多层子查询。
- 分页优化:用
WHERE id > ?
替代OFFSET
。
9.2 索引优化
- 添加索引:覆盖查询字段。
避免失效场景:
- 函数计算(如
WHERE YEAR(create_time) = 2023
)。 - 模糊查询(如
LIKE '%keyword%'
)。 - 隐式类型转换(如字符串字段用数字查询)。
- 函数计算(如
9.3 架构优化
分库分表、读写分离分散压力。
10. Redis 数据类型
- String:字符串、整数。
- List:有序列表,支持双向操作。
- Hash:键值对集合,适合存储对象。
- Set:无序唯一集合。
- ZSet:有序集合,按分数排序。
11. Hash 的典型使用场景
- 存储对象:如用户信息(字段为
name
,age
)。 - 配置管理:多个键值对的高效存取。
- 缓存组合数据:避免序列化整个对象。
12. 代码题:有序数组查找(二分法)
func binarySearch(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)/2
if nums[mid] == target {
return mid
} else if nums[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return -1
}
要点:
- 循环条件
left <= right
。 - 中间值计算防溢出(
mid := left + (right-left)/2
)。
早日上岸!
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:sf面试群。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。