写点什么

大厂外包 VS 小公司,你会怎么选?

作者:王中阳Go
  • 2025-05-22
    湖南
  • 本文字数:2084 字

    阅读完需:约 7 分钟

大厂外包VS小公司,你会怎么选?

很多朋友在找工作的时候都会遇到各种外包岗,今天分享的面经就是出自组织内部的朋友在百度外包的面试;


看到这个岗位我就有点好奇,如果同时拿到了大厂外包的 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 的类型分为以下三种:


  1. 双向通道:默认类型,可发送和接收数据,例如 chan int

  2. 只读通道<-chan T):仅能接收数据。

  3. 只写通道chan<- T):仅能发送数据。

  4. 通过类型转换可实现只读或只写的限制,例如:


ch := make(chan int)var readOnly <-chan int = ch   // 只读var writeOnly chan<- int = ch  // 只写
复制代码



5. 实际应用最常用哪种

实际应用中,带缓冲区的双向通道最常见。例如:


  • 任务队列:通过缓冲通道实现异步处理,提升吞吐量(如 make(chan Task, 100))。

  • 流量控制:结合 select 和缓冲区限制并发数。

  • 无缓冲通道多用于同步场景(如信号通知),但带缓冲的通道更灵活且性能更优。



6. 并发编程常用指令

  1. 协程创建go func() { ... }()

  2. 通道操作

  3. 发送数据:ch <- data

  4. 接收数据:data := <-ch

  5. 同步工具

  6. sync.WaitGroup:等待多个协程完成(Add(), Done(), Wait())。

  7. sync.Mutex/sync.RWMutex:保护共享资源。

  8. sync.Map:线程安全的映射。

  9. 通道选择select 处理多通道操作。

  10. 原子操作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 表设计

  1. 业务拆分:通过逻辑外键关联(如用户表与订单表)。

  2. 字段设计

  3. NOT NULL 约束避免空值。

  4. 合理选择类型(如 INT vs VARCHAR)。

  5. 索引优化:高频查询字段(如用户 ID)添加索引。

  6. 分库分表:数据量大时按哈希或范围分片。

8.2 并发控制

  1. 读写分离:主库写,从库读。

  2. 缓存热点数据:Redis 缓存高频查询结果。

  3. 流量削峰:Kafka 异步处理请求。



9. 慢查询优化

9.1 SQL 优化

  1. 精简查询字段:避免 SELECT *

  2. 优化 JOIN:避免多层子查询。

  3. 分页优化:用 WHERE id > ? 替代 OFFSET

9.2 索引优化

  1. 添加索引:覆盖查询字段。

  2. 避免失效场景

  3. 函数计算(如 WHERE YEAR(create_time) = 2023)。

  4. 模糊查询(如 LIKE '%keyword%')。

  5. 隐式类型转换(如字符串字段用数字查询)。

9.3 架构优化

分库分表、读写分离分散压力。



10. Redis 数据类型

  1. String:字符串、整数。

  2. List:有序列表,支持双向操作。

  3. Hash:键值对集合,适合存储对象。

  4. Set:无序唯一集合。

  5. 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,备注:infoq 面试群。

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

王中阳Go

关注

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

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

评论

发布
暂无评论
大厂外包VS小公司,你会怎么选?_Go_王中阳Go_InfoQ写作社区