你好,我是yes。
今天刷到一个帖子,看到之后有点唏嘘,现在实习面试题都这么难啊!
搁我那时候,一个 SSH 杀到底,都问些啥面向对象三大特性,然后三次握手啥的差不多了。
我们来看下这位小伙伴面试字节跳动技术中台暑期实习一面的面试题:

TCP 有什么值得改进的地方

这个问题其实挺考验人的。
能答出这个问题首先需要了解 tcp 的所有特性,然后对一些场景有自己的思考。
TCP 身为传输层协议,已叱咤江湖多年,本身没有什么严重的缺陷,无非是因为有些场景,导致 TCP 的特点变成缺点。
比如直播的业务场景下,更适合用 UDP,TCP 的可靠性传输在这个场景反而是缺点。
所以,我们要基于 TCP 的特性出发,结合实际,从另一个方面考虑这个特性可能产生的问题。
我举个例子,比如 TCP 是基于四元组的(源IP地址、目的IP地址、源端口、目的端口),那假设我们网络切换了(从外面回到家,5G变wifi),或者之前的连接超时了,后面重连了个,但是 IP 换了,这种情况,四元组变了。
而四元组的变化就导致之前的连接不可用,于是需要重新建连,建连我们都知道有时延(三次握手),所以这是不是一个值得改进的地方(追求体验极致)?
还有 TCP 保证有序性,导致队头阻塞的情况,我们拿 HTTP 使用 TCP 来说说。
我们都知道 HTTP1.1 有个 Pipelining 机制,允许基于一条 TCP 连接同时发送多次 HTTP 请求
图来自网络
但是对 HTTP 响应的顺序还是有要求的,必须等待第一个 HTTP 请求返回,后面的请求才能返回。
基于这一点 HTTP2.0 利用多路复用,将请求拆成多个帧来传输,但是这其实没有解决 TCP 队头阻塞的情况,因为底层还是利用 TCP 传输的,TCP 是有序的。
虽然拆成了多个帧,但是前面的帧没返回,后面的帧其实也会被阻塞,在这种场景下 TCP 也需要改进。
还有 TCP 的拥塞控制算法,我看帖子评论区很多同学提到了 BBR,这挺好的,但是这拥塞算法是 TCP 的一部分,不能认为不是一个值得改进的地方。
小贴士:BBR 是Google 2016年发布的拥塞算法,之前大部分拥塞算法是基于丢包的情况来降低传输效率,而 BBR 会基于模型主动探测。
但是我们可以从拥塞控制算法的灵活替换来说, TCP 其实有好多拥塞控制算法的实现:
  1. TCP Tahoe 和 Reno
  2. TCP Vegas
  3. TCP New Reno
  4. TCP Hybla
  5. TCP BIC 和 CUBIC
  6. TCP Westwood和Westwood+
  7. Compound TCP
  8. TCP PRR
  9. TCP BBR
我在维基百科上面看到有这么多算法实现,不同算法其实有不同的适配场景,比如:
我们都知道,TCP 相对而言是比较底层的,不像我们 HTTP 协议,身处应用层可以很方便的替换,所以它不太方便我们基于不同场景灵活替换合适的拥塞控制算法,要扯的话其实这也是一方面。
好了,不吹牛了,以上其实就是 QUIC 协议针对当前 HTTP/TCP 协议的缺点作的一些优化。
QUIC 协议底层用的是 UDP,然后自己实现了一套机制保准了传输的可靠性,从这个角度理解,其实就是嫌弃 TCP 不好,所以这个问题从 QUIC 解决 TCP 的一些问题来回答是再合适不过啦。
更多细节同学们自行去查阅 QUIC 相关资料吧!

给你一个四核CPU 计算圆周率,你的最大线程池参数和核心线程数会怎么设计呢

给你一个四核CPU 计算圆周率
这一句话表明你这个线程池将要运行的任务是 CPU 密集型,也就是说基本上 CPU 在做纯运算,不需要等待。
与之对应的是 IO 密集型,IO 密集型的话,CPU 的利用率就不会很高,因为 CPU 跑着跑着需要等待 IO (数据库的读取,文件的读写,网络请求等)的返回。
基于这两种特性,线程池的参数是不一样的。
你可能会在网上或者书上看到很多配置公式,比如:
  • CPU 密集型的话,核心线程数设置为 CPU核数+1
  • I/O 密集型的话,核心线程数设置为 2*CPU核数
不过,线程数真的很难通过一个公式一劳永逸,以上只是一个理论值,线程数的设定是一个迭代的过程,需要压测调整,以上的公式做个初始值开始调试是 ok 的。
所以初步判断核心线程池其实 4 就够了,最大线程数可以设置为 5。
总结下这题的回答思路:跟面试官分析下是 CPU 密集型,然后说初始值可以设置为 CPU核数,最后设定还是需要压测,根据实际业务场景的情况再来调整线程数

线程和进程的区别,除了它们资源持有者和调度单位外

其实我也不知道这个问题面试官打算问啥,因为它们之间最显著的区别就是资源和调度。
线程是程序执行的最小单位,进程是操作系统分配资源的最小单位
既然这两个最显著的区别排除了,我们就从别的角度入手,比如我们常提到的上下文切换。
其实一开始是没有线程的,只有进程的概念。
而随着计算机的发展,对运行的要求越来越高,计算机同时运行的程序也越来越多,进程作为最小调度单位就显得太大了
因为进程是资源分配的最小单位,切进程其实就是切资源,再具体点(影响最大的)其实就是虚拟地址空间的切换。
每个进程都有自己的虚拟地址空间,即需要有页表,把虚拟地址映射到物理地址,而这个页表需要频繁访问,所以 CPU 会做 cache,即 TLB(Translation Lookaside Buffer)。
如果切换进程,页表就换了,这个 cache 就失效了,失效了之后,虚拟地址转换为物理地址就变慢,这就导致程序变慢。
所以后面抽象出线程,我们知道一个进程里的线程是共享内存空间的,所以一个进程内部线程切换是不需要更换页表的。
因此,这个问题我们可以从线程和进程上下文切换的角度入手来回答。
当然,我也不知道这是不是面试官想要的答案,仅供参考。

最后

好了,我个人认为这类问题对暑期实习同学来说,确实有点难。
换位思考下,如果是身处大学的我肯定答不出来。
但是,从帖子评论区有这么多同学能说出 QUIC 等关键词来看,其实这类问题也真不是为难人。
因为有人可以联想到这块,说明有人可以答出来。
近年来网上的资料越来越多,像我以前看 B 站都是看鬼畜,现在上面源码讲解的一大堆,对应到面试官身上,需要通过更难、更复杂的问题来筛选候选人。
你想想,你要是面试官,你问个题目,100个人里面有99个能答出来,那问的意义就比较小,总不可能 99 个都招进来吧?
所以,只能出一些 100个人里面只有几个人能答出来的,这样才便于企业筛选合适的候选人,这是没办法的。
那怎么办呢?只能学咯,平日学习还要多思考,其实很多问题你只要有自己的想法,就很容易进行联想,进行延伸,能跟面试官多来个几回合,这样更容易脱颖而出,拿下 offer!
最后祝各位 offer 拿到手软,我这边提供一个有关面试的服务,最近大概跟10多位小伙伴操作了下,反响还行,有兴趣的可以看看
我是yes,我们下篇见~
继续阅读
阅读原文