2

今天分享的是粉丝投稿的在腾讯的最新面经,问的都是一些高质量的问题,看看你能答上来几个:


1. Proactor和Reactor模式的区别?

核心区别:事件处理流程不同

  • Reactor:基于同步I/O,主线程监听事件就绪后,由工作线程执行实际I/O操作(读/写)和业务处理。典型代表:Linux epoll
  • Proactor:基于异步I/O,主线程直接处理I/O操作完成后的事件通知,工作线程仅处理业务逻辑。典型代表:Windows IOCP

2. 栈和堆的内存管理差异?

分配方式编译器自动分配/释放GC自动管理
内存碎片可能产生碎片
访问速度快(CPU缓存友好)较慢(需寻址)
逃逸分析函数内部分配跨函数共享时逃逸

3. Slice的底层存储结构?

type slice struct {
    array unsafe.Pointer // 指向底层数组
    len   int
    cap   int
}
  • 存储位置:slice头结构可能在栈或堆,底层数组始终在堆
  • 关键特性:自动扩容(cap不足时2倍增长),共享底层数组

4. 说一下grpc和http2.0

gRPC

  • 简介:是Google开发的高性能开源RPC框架,能让客户端像调用本地方法一样调用远程服务器上的方法,方便构建分布式系统和微服务架构。
  • 特点

    • 以高效、紧凑的ProtoBuf作为默认数据序列化格式。
    • 支持Java、C++、Python、Go等多种编程语言,便于异构环境集成。
    • 支持双向流通信,客户端和服务端可同时收发多个消息,提升通信灵活性与效率。
  • 应用场景:常用于微服务架构中微服务间通信、云原生应用以及移动应用与后端服务通信等场景。

HTTP/2.0

  • 简介:是HTTP协议的第二个主要版本,对HTTP/1.x进行了重大升级,以提升网络传输效率和性能。
  • 特点

    • 采用二进制分帧传输数据,数据解析和处理更高效,传输更可靠。
    • 支持多路复用,可在同一个连接上同时发送多个请求和响应,解决了队头阻塞问题,提高连接利用率,减少延迟。
    • 运用HPACK算法对头部进行压缩,降低了头部数据传输量,提高传输效率。
  • 应用场景:广泛应用于Web应用、CDN内容分发等需要高效网络传输的场景,能优化网页加载速度,提升用户体验。

5. Protobuf是什么

基本概念

是一种与语言、平台无关的序列化方式,能把结构化数据转成字节流传输或存储,也可从字节流恢复数据,类似XML和JSON,但有独特优势。

核心特点

  • 高效:采用二进制编码,比XML和JSON等文本格式空间占用小、处理速度快,可减少带宽和存储成本,提升数据处理效率。
  • 多语言支持:支持Java、C++、Python等多种编程语言,不同语言系统间能方便地用它交换数据。
  • 可扩展:定义数据结构时能添加新字段,旧代码解析含新字段数据时会忽略新字段,保证向前兼容性,便于数据结构升级。
  • 强类型:定义数据结构时要明确字段数据类型,有助于编译时发现错误,提高程序稳定性和可靠性,也让数据处理更高效准确。

工作原理

  • 先在.proto文件定义消息形式的数据结构。
  • 用Protobuf编译器生成特定编程语言代码,包含序列化、反序列化方法及操作字段的接口。
  • 发送端将数据填进消息对象,序列化转成字节流发送或存储;接收端读取字节流,反序列化恢复成消息对象来处理数据。

6. Goroutine与线程的核心区别?

GoroutineOS线程
内存开销2KB初始栈1-2MB栈空间
创建速度0.3μs10μs
调度方式用户态GMP调度内核态调度
切换成本120ns1-2μs

7. Go的并发原语对比JS Promise?

Go特性

  1. goroutine + channel实现CSP模型
  2. sync.WaitGroup控制并发等待
  3. context实现超时控制
    对比差异
  4. 无链式调用语法
  5. 通过select实现多路复用
  6. 原生支持并发安全Map(sync.Map)

8. 线程安全的LRU实现方案?

type SafeLRU struct {
    sync.RWMutex
    cache *lru.Cache
}

func (s *SafeLRU) Get(key string) interface{} {
    s.RLock()
    defer s.RUnlock()
    return s.cache.Get(key)
}

// 使用hashicorp/golang-lru实现基础LRU

优化方案

  1. 分片锁(Sharded Lock)
  2. 原子操作替代锁(适用于计数器场景)
  3. 无锁队列(sync/atomic实现)

9. sync.Pool的使用场景?

  1. 缓存临时对象,减少GC压力
  2. 网络连接池复用
  3. 大内存块复用

注意要点

  • 获取的对象可能残留旧数据
  • 不适合存储有状态资源
  • GC时会清空Pool

10. TCP粘包解决方案?

  • 定长分包:按固定长度分包数据,接收方依此读取,适用于数据长度固定的场景,如固定格式的协议数据。
  • 特殊字符分隔:在包尾加特殊字符或序列作分隔符,接收方据此判断包边界,适用于数据不包含分隔符的情况,如文本协议。
  • 消息头记录长度:在包头部设字段记录包长,接收方先读长度字段,再按此长度读取数据,适用于数据长度不固定的情况,通用性强。
  • 使用应用层协议:在应用层定义协议,规定数据包格式等,通过解析协议处理粘包,如HTTP协议,适用于需复杂数据处理和交互的场景。
  • 基于框架或库:利用Netty、Twisted等成熟框架或库处理粘包,它们有内置处理机制,适用于使用相应框架开发的项目,可简化开发。

11. 值传递 vs 指针传递?

值传递指针传递
内存分配栈拷贝传递指针地址
修改影响不影响原值影响原值
适用场景小结构体(<64B)大结构体或需修改

12. 分片上传的实现?

典型方案

  1. 前端计算文件hash(spark-md5)
  2. 服务端预检分片状态
  3. 并行上传分片(每个分片单独PUT请求)
  4. 服务端合并分片
    Go实现要点
  5. 使用sync.Pool管理分片缓冲区
  6. 采用文件锁保证合并安全
  7. 支持断点续传(记录分片状态)

13. Slice与List的差异?

SliceList(container/list)
内存布局连续内存双向链表节点
随机访问O(1)O(n)
插入删除O(n)O(1)
缓存友好

14. GC调优策略?

  1. 减少堆内存分配(复用对象)
  2. 控制对象生命周期(及时设为nil)
  3. 调整GOGC参数(默认100)
  4. 使用pprof分析内存分配
  5. 避免大内存对象(拆分slice)

15. Context的核心作用?

  1. 传递请求上下文(traceID等)
  2. 超时控制(WithTimeout)
  3. 取消传播(WithCancel)
  4. 值传递(WithValue)

正确用法

  • 作为函数第一个参数传递
  • 线程安全,应传递副本而非引用
  • 值传递只用于请求域数据

    以上就是面经的全部内容,希望对你有帮助。

欢迎关注 ❤

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

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

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


王中阳讲编程
833 声望320 粉丝