慎终追远,民德归厚矣。

腾讯新闻pcg 实习 一面挂

面试官自我介绍

本人自我介绍

项目 15min

  1. 介绍一下第一个项目
  2. 项目难点在于?
  3. 提到的高精准和高负载,其中高精准是怎么做到的?
  4. 比如说我现在创建一个,在二十一点二十七分,每五分钟创建一个。嗯,执行一下脚本,然后你是,你说你未来 24 小时你会创建每 5 分钟有一个任务,是吧?落在不同的那个
    解释了一下数据冷热分区,只会迁移未来两小时的数据
  5. 任务是否可以取消?
  6. 比如说你这个桶里面有没有出现?桶里面还有,已经有这个任务了,但是我的表里面已经的任务是一个 cancel 的一个状态,然后他又会还在继续在执行着,有没有可能?
  7. 讲一下第二个项目的架构和原理

系统 15min

  1. 说一下操作系统的几个核心模块?
    搞的我有点懵(八股选手是这样的),后来稍微提醒了一下,说了进程管理、内存管理、文件管理、网络管理。。。
  2. 说一下进程管理?
    按照自己的理解说了一遍
  3. 了解进程间通信有哪些方式?
    吟唱
  4. 说一下你理解的系统调用?
    这里说的比较深、涉及到的cpu上下文切换、态目转换、用户栈变为内核栈的细节都说了
  5. 说一下内存管理?
    主要讲了虚拟地址的作用,以及分页相关的
  6. 说一下内存管理有哪些分配算法?
    (没背过,不知道)
    • 首次适应算法(First Fit)
      将空闲分区链以地址递增的顺序连接;在进行内存分配时,从链首开始顺序查找,直到找到一块分区的大小可以满足需求时,按照该作业的大小,从该分区中分配出内存,将剩下的空闲分区仍然链在空闲分区链中。
    • 循环首次适应算法(Next Fit)
      分配内存时不是从链首进行查找可以分配 内存的空闲分区,而是从上一次分配内存的空闲分区的下一个分区开始查找,直到找到可以为该进程分配内存的空闲分区;
    • 最佳适应算法(Best Fit)
      将空闲分区链中的空闲分区按照空闲分区由小到大的顺序排序,从而形成空闲分区链。每次从链首进行查找合适的空闲分区为作业分配内存,这样每次找到的空闲分区是和作业大小最接近的,所谓“最佳”。
    • 最坏适应算法(Worst Fit)
      与最佳适应算法刚好相反,将空闲分区链的分区按照从大到小的顺序排序形成空闲分区链,每次查找时只要看第一个空闲分区是否满足即可。
  7. 说一下文件系统?
    (没背过,不知道,小林coding上的没看。。。)

网络 15min

  1. 操作系统里的网络主要干了什么事?
    绕弯了,说的就是七层模型,吟唱

  2. 说一下TCP和UDP
    吟唱

  3. 你有写过TCP和UDP的程序嘛?
    不愧是你腾,喜欢考网络编程(不会)

  4. 问一个比较有挑战性的问题:现在我有一台服务器,嗯,内存还比较大,实际上 100 多g, 100 多g。然后我这个服务,我先跑个程序,让你写个程序实现百万级设备的连接,然后实现文件的一个传输。你,你大概怎么做?
    刚开始有点懵逼,后来想到这不得用IO多路复用嘛,说了一下epoll的流程,优势,之后epoll_wait之后怎么读数据就不知道了。。。(这里面试官表示可惜)
    查了一下,其实后续的数据传输就是很简单的思路,过 epoll_wait 获取活动的文件描述符,参考零拷贝技术sendfile可以在内核传输的特性,以及大块读取文件减少IO的思想,给出gpt的思路:(怪不得可惜的。。。)

    1. 监听连接:首先,你会通过 epoll_create 创建一个 epoll 实例,监听多个设备的网络连接(使用 epoll_ctl 加入监听)。
    2. 处理连接的事件:通过 epoll_wait 获取活动的文件描述符(比如有数据可读、可写等),然后分别处理:
      • 接收数据:如果是接收文件数据,可以使用 recv()read() 等阻塞函数,或者为了更高效可以考虑使用非阻塞模式,配合 epoll 监听文件描述符的可读事件。
      • 发送数据:如果是发送文件数据,也可以通过 send()write() 完成,确保数据传输的过程中不会阻塞。
    3. 数据传输:对于大规模文件传输的部分,你可以通过大块读取和写入来减少 I/O 次数,从而提升效率。例如:
      • 可以通过 sendfile 进行文件传输,它通常比 read()/write() 组合更高效,因为它能在内核空间直接实现数据传输,避免了用户空间与内核空间的数据复制。
      • 对于百万级连接,数据发送和接收应该是异步的,可以借助 epoll 监听文件描述符的可写事件,然后在准备好发送数据时再写入,避免阻塞。
    4. 内存管理:因为内存足够大,可以利用内存映射(mmap)来提高文件操作的效率,将文件直接映射到内存中,然后通过指针操作来完成数据的读取和写入,减少不必要的 I/O 操作。
    5. 并发处理:如果单线程处理效率不够,可以考虑使用多线程或者多进程来分担任务。每个线程或进程可以处理一定数量的连接,通过线程池或进程池来管理。
    6. 负载均衡:考虑到你可能会有大量的设备同时连接,可能需要使用负载均衡算法将连接分配到不同的工作线程或进程中,这样可以避免单个线程或进程成为瓶颈。

    总结来说,你的思路基本是对的,接下来就要精细化地处理每个事件的具体操作,保证系统高效处理百万级的连接和大规模的数据传输。在实现中,I/O 多路复用和异步 I/O 是核心部分,同时内存管理和文件传输效率也非常重要。

算法&场景题 30min

  1. 对你算法的自我评价
  2. 说一下你了解的有哪几种排序算法
    冒泡、快速、归并、堆排序
  3. 堆是什么树,普通二叉树?完全二叉树?满二叉树?
    完全二叉树
  4. 怎么实现删除堆里的任意一个元素?
    这里刚开始就想到的是,讲最后一个元素和待删除的元素替换,然后不断的down,面试官说有点问题,但是我自我怀疑很久,不知道那里有问题,面完了才知道是自己傻逼了,不仅要down,还要up(这里面试官表示第二次可惜)
  5. 场景题:现在有一个1T的数据存放在磁盘上,但是内存只有1M,我现在想要把所有数据变得有序,最后存在磁盘里,说说思路
    这里不就是典型的外部排序嘛,先分治,文件分块,保证能装进内存,挨个排序,得到很多有序的小文件,最后创建一个文件数量大小的小根堆,依次遍历每个文件的每个头元素,放进去,取出堆顶,写入最终的文件里
    面试官说这里IO太大,多路归并有点问题,后续怎么处理,(实在没想到,他表示第三次可惜,都说到这份上了,最后差点意思,感觉是有点不按套路出牌的,人家都问的是取前10或者前100,他直接就全部排序,还是很有难度的。。。还是没想清楚,后面即使成批量读取减少IO之后应该怎么搞,问了gpt感觉也不是很合理)

面试官整体评价:前半程很不错,后面的算法开始有点出乎他的意料(确实是个很简单的堆问题),算法差点意思,场景题有思想,但不够,也差点意思。。。(最后时间原因就没有写算法题了)