目录

0.引言与视频连接

1.多进程和多线程实现并发的编程的优势和劣势是什么?

2.协程为什么能实现更高的并发?

3.下面哪种访问数组的方式更快?

4.斐波那契数列(Fibonacci sequence)

5.哈希表和二叉查找树各自的优缺点

6. 解决hash冲突的方法及各自优缺点

7.谈谈自旋锁

8.读写锁用于解决什么问题-读优先和写优先是什么意思?

9. 怎样一个磁盘上的文件快速发给客户端?

10.相比堆,为什么栈上分配对象的速度更快?


0.引言与视频连接

https://www.bilibili.com/video/BV1nQ4y1T7FA
陶辉老师简历:
北京广东信达有限公司--2004年网管
华为--网管
腾讯--2007年--面试官猫眼CEO郑志昊Peter
思科--wedfx--但是全球最大的一个视频会议系统
阿里云
创业https://baike.baidu.com/item/%E9%83%91%E5%BF%97%E6%98%8A/7257297?fr=aladdin--郑志昊百度百科性能面试中很重要,在晋升中也很重要.
性能需要沉下心学习,如果对性能有深耕,写出的代码会质量很高.

1.多进程和多线程实现并发的编程的优势和劣势是什么?

  切换的代价是不一样的,涉及到地址空间的问题,多进程挂了不会影响到其他进程,每个进程都有独立的进程空间,所以Nginx使用多进程,它是特别强调稳定性.老师说的evoal?是啥--多线程的.一个线程一旦挂了,就会把整个进程中的所有线程的地址空间都写乱,就全部挂了.多进程的劣势:因为是独立的地址空间,所以通信起来就相对困难.线程通过共享内存就可以实现通信了.我的想法:其实俺觉得,通信困难也是相对的,毕竟人家多进程有那么多种通信方式.

2.协程为什么能实现更高的并发?

1.切换速度非常快,进程和线程如果要切换需要在内核态进行切换,但是协程是在用户态进行切换,所以不用进入内核态的话,上下文切换的成本就没有了;
2.和异步编程有关,因为我们在网络编程中使用多线程的时候往往使用同步的阻塞的socket,磁盘IO的编程也有同样的道理,如果调用一个阻塞的API,如果没有完成任务就让线程休眠,使用协程则一般不会用阻塞的API,协程默认会创造一套无阻塞的生态,这个生态中所有的API和SDK都是没有阻塞的,可以让协程自己在用户态进行调换;
3.实现高并发的瓶颈是什么呢?比如说一个百万连接吧.每一个连接都是要占用内存的,比如说在linux下线程有对应内存池的概念,默认情况下开一个线程会分配64M内存(非常恐怖),所以很多时候Java程序员在JVM启动之后会多出几个G的内存,这个其实是线程的内存池造成的,所以我们想100w并发请求,线程是绝对做不到的,除了线程的area(堆内存),还有响应的栈部分的内存,每一个线程都会有自己的栈(大概是8M,这个是可以设置的),这个内存要求是不可能支撑百万连接的.协程的优势就有了,一个协程所占内存只有十几K或者几十K,所以可以轻松实现百万甚至千万并发.

3.下面哪种访问数组的方式更快?

方法1
for(i=0;i++;i<n)for(j=0;j++;j<n)array[i][j]方法2
for(i=0;i++;i<n)for(j=0;j++;j<n)array[j][i]本题考查的是CPU缓存,本题有三点:
(1)内存布局,二维数组的大部分编程语言都是按行布局的,一行数据放完了再放第二行,以此类推,
基于这个概念,我们再来看CPU的缓存;
(2)CPU中的缓存;
(3)CPU中的缓存行的大小.如果想要把系统的性能优化到极致,您必须清楚地了解主机相关的几大件(CPU,内存,磁盘,网络等)的
速度到底有多快.一台好的电脑可能会有3级CPU缓存,普通的可能有2级CPU缓存.一般来说访问速度大概
如下:
寄存器       1nm
一级CPU缓存  3-5nm
二级CPU缓存  10-20nm
三级CPU缓存  20-30nm
内存         100nm
为什么要有缓存呢?因为可以提前把需要访问的数据批量地载入到缓存,缓存的数据非常快,CPU就不用
总是在等待,因为每次计算一个数据都需要把程序的指令读到CPU运算,想要写回去也会很慢,有了缓存,
缓存和内存之间的通讯就相对独立开了,CPU就可以全力工作起来了,所以我们此时必须清楚,访问
array[i][j]的时候是批量载入缓存中的,array[i][j+1],array[i][j+2],array[i][j+3]等都被载入
到缓存中去了,所以arr是一个数字的情况下,一次性会载入一个CPU_Cache_Line(目前是64字节)个字
节,如果每个元素是8字节的,一次性可读入8个数组元素,此时array[i][j]可以利用这个特性,但是
array[j][i]就无法利用这个特性了,因为它是按列进行布局的.这道题的思想和我们息息相关,优秀的开源项目中的代码中都会充分利用这个特性.功能相同的代码,
为什么有的快有的慢,有的甚至相差很多,也许就是这些细小处的原因.
C++语言下的遍历arr[i][j]可以比arr[j][i]快7倍多,如果java可能也会快一些,python中可能也有
区别,具体要看封装细节和测试结果.从这个细节,我们可以发现好的开源代码作者非常关注CPU缓存,内存池中的问题,这些都体现了功力
的问题,但愿我们都能成十倍程序员.--局部性原理斐波那契数列(Fibonacci sequence)

CPU的Cache与缓存行

Linux上查看缓存行的大小

4.斐波那契数列(Fibonacci sequence)

谷歌一道非常有意思的面试题,考查以下点:
1.递归概念;
2.时间复杂度,我们在谈性能的时候,一定要从算法复杂度这个概念去思考的.能不能从递归函数中推导出2的n次方,这个在现实中非常复杂的,几乎不能用;
3.能不能优化,将时间复杂符从2的n次方降低到n,换一种方式,可以自顶向上计算,计算完1计算2...倒着推,一个for循环就可以解决.
4.用公式法,展现您的数学功底,震惊你的面试官吧,实现O(1)复杂度.

5.哈希表和二叉查找树各自的优缺点

基本概念:
二叉树:每个结点最多有两个小孩;
二叉查找树:是一个有序的二叉树;
平衡的二叉查找树:如红黑树.回答本题需要注意:
(1)CRUD的各自时间复杂度,红黑树logn,哈希表好的情况下是O(1),比较好的情况下,哈希表是快于红黑树的;
(2)要说明缺点:哈希表:a.哈希表的遍历的性能不能满足我们的需求,特别当我们希望哈希表的冲突比较少的时候,在设计及的后序实现的时候,会产生很多空槽(空的bucket),也就是说此时的装载因子是比较小的,这时遍历会做很多无用功,可以遍历但效果会比较差;b.做范围查询查不了,因为是基于hash函数,映射到一个位置,但是查找另一个key对应的值的时候,可能key是相邻的,但是value完全没有什么关系,就没有办法做范围查询,但是范围查询又是我们很多时候会经常用到的,所以这个是哈希表的问题.二叉查找树:a.平衡的问题;b.当元素很多的时候,树高称为一个问题,针对树高太高的问题此时我们就可以考虑其他类型的树,比如 说我们现在做一个索引支持范围查询的时候就使用了B+树,B+树的底层数据会放到磁盘中.

6. 解决hash冲突的方法及各自优缺点

不同的key可能会映射到同样一个位置上,有时候我们的key非常大,比如说是一个字符串,但是
位置是很小的,因为hash表是有限的,位子其实就是在数组中的一个位置,这个数组可能非常小,
但是前面的信息量是非常大的,一般来说都要进行压缩的,这样下来冲突就不可避免了.哈希冲突的两种方法:
(1)开散列:在hash数组之外去存放有冲突的元素,也叫作链表法,当多个元素映射到同一个元素的时候就变成一个链表了,此时的查询时复杂度会退化成O(n);
(2)闭散列:冲突之后,换一个hash函数,会产生一组hash函数,这一组hash函数可以与我们的冲突次数相关.比如说有一个新的key存入的时候发现冲突了,就换第二个哈希函数,其中第二个hash函数,第二个哈希函数中可以引入一个冲突次数,整个函数中将冲突次数作为一个自变量引入,最后得到的结果就变了,所以位置就自然地变了,这个就是闭散列.(1)开散列:哈希函数设计相对简单;在容灾场景中特别适合用作持久化;
(2)闭散列:对哈希函数的设计要求复杂一些.在腾讯的工作中,陶辉老师曾经设计过一个hash表,这个hash表需要跨服务器对数据进行存放,需要容灾,
当出现问题的时候需要从另一台服务器将数据再弄过来,这时候如果使用开散列就非常糟糕了,因为首先
为了速度这个哈希表是放在内存中的,其次为了传到另一台服务器肯定是要序列化的(如果通过其他的方
法来做序列化是无法控制的),最快的方法就是利用映射,把内存映射到磁盘中,此时如果有链表,想要映
射就非常困难了,需要很多逻辑并做很多事情.但此时如果是一个闭散列,就会特别简单,把整个数组映射
下来作为一个文件传到另外一台机器上就可以了.
所以闭散列在持久化上的优势非常大,一般来说,在分布式的容灾上,闭散列是非常香的.场景思考:
一个数据库一个用户表已经存不下了,再放性能就会变很差,需要通过hash函数将其挪一下位子,取模,
比如说有10张表就模10,32表就模32,就可以换到不同的表上去.一个好的哈希函数:
(1)减少冲突,扩容,当内存不值钱的时候,可以将装载因子变小,100个槽位只用10个,就能很好散列;
(2)运算速度快,需要充分考虑位运算和数学上的知识.
(3)动态扩容.哈希表的扩容是一个比较麻烦的事情,最简单的是停下来重新映射,映射到一个扩容后的哈希表,但这时哈希表的可用性为0了,这个不是最优解.所以我们提出“动态扩容”,一边迁移一边为客户提供服务,
如果访问到某个值,可以稍微慢一点,但是迁移要持续下去.
动态扩容涉及到单机内和跨服务器的,但道理是一样的,关键是要有一个标签能给出这个值现在是在老
哈希表中还是新哈希表中,用异步的一个线程逐步扩容,每次查询的时候先判断在新表还是旧表中即可.因为数据一般是有规律的.腾讯QQ号分库分表的时候,最初是模100,这个会把
最后具有很低辨识度的两位数字的影响放大,对靓号的追求会使得有些人们眼中的好号码的热点很高,
有些数字遭受冷落,QQ号最后两位数便是靓号的一个重点,所以模100是个很糟糕的方法.
之后改成99,其实也不是最好的.从数学上来说,mod一个较大的素数,比如说101等素数对解决冲突来说
非常好.模32是个非常糟糕的方法,一个懂得性能优化的程序员,写代码的时候写mod32和右移5位相比,右移5位
的效率要高很多;
java的标准库中对字符串求hash的时候就用到了一个质数31,每个字符的ASCII码乘以31,左移五位再
减去n和乘以31的数值是一模一样的;--这一点没听明白..
手机号做主键,前三位(运营商)是个很糟糕的选择,中间四位(区域)也是一个糟糕的选择,后四位相对
来说就是一个比较好的选择,身份证也需要做同样的考虑.

7.谈谈自旋锁

自旋锁--世界上最不撞南墙不回头的锁.自旋锁和互斥锁场景比较:
自旋锁:比如有个洗手间里面有个人,我很着急,我就一直敲门敲敲敲敲敲催ta出来;
互斥锁:比如有个洗手间里面有个人,我不是很着急,我敲了一下门,没出来,我就不敲了,等ta出来,我就有机会进去,但是要注意ta出来了以后能进去的不一定是你噢.有啥差异:忙等待和休眠等待;
自旋锁:一直在等;
互斥锁:等的时候可以看看电影啥的;锁的选择涉及到应用场景:
如果你是要做一个在几步内就能完成的操作,比如说对一个整型变量赋值,对一个字符串赋值,简单地计
算,这种情况下使用自旋锁是最合适的.因为此时基本没有什么性能损耗,不会发生线程切换等行为,而互
斥锁会导致调度任务(线程)发生切换,这个是有代价的,linux下差不多有几毫秒.本题考查:
(1)自旋锁的实现,表面上是忙等待,但是绝对不能写个while(1)让ta空转,会导致CPU的使用100%,向intel之类的提供商会提供pause这样的指令(可以省电),不至于导致CPU一直在转耗电太大;
(2)判断一块代码的执行时间,在实际应用中判断这块代码到底适不适合使用自选锁.

8.读写锁用于解决什么问题-读优先和写优先是什么意思?

如果能够区分对资源要做的操作是读或者是写,就可以用读写锁.
读锁共享资源,写锁独占资源.使用场景:读多写少.
读写锁的实现方式:大部分使用互斥锁实现,也可以用自旋锁实现.读优先:
1号线程在读,2号写线程来了等着,3号读线程来了可以共享一号的读锁,4号读线程来了可以共享一号的
读锁...会造成2号写线程饿死(写线程饿死的前提是一直有读线程占着锁,一旦出现锁释放没被占用,就会
被写线程拿住);写优先:
1号线程在写,2号读线程来了等着,3号写线程来了一旦一号的写锁释放立刻拿到,4号写线程优先级也比
读线程优先级高...会造成2号读线程饿死;JAVA中为了防止线程被饿死,设计出retrainreadwritelock这样的锁,公平读写锁,会把没拿到锁的线程
安排进一个队列中,会有优先级,效率稍低,但不至于有线程被饿死.

9. 怎样一个磁盘上的文件快速发给客户端?


传统的方法:
大小不知道,一般不会分配较大块内存,如果一个文件1G,要在内存中分配1G,100M的压力
可能都会很大,可能直接就OOM了.所以可能在用户空间定义一个比如说32K的空间每次读32K,
再往网络上发送.传统的方法问题:
(1)内存拷贝次数太多:磁盘文件会首先拷贝到操作系统的一个高速缓冲区,再从高速缓冲区拷贝到用户态分配的那32K,再把32K拷贝到内核分配的socket缓冲区,再把socket缓冲区的内容拷贝到网卡上.4次拷贝.
(2)切换次数多:调用一次read,会发生两次切换(从用户态切换到内核态,再从内核态切换到用户态); 调用send也是两次切换.解决方案:调用sendfile.
零拷贝的优点:
(1)两次系统(read和send)调用变成一次(sendfile),拷贝也少了;
(2)充分使用了tcp的缓冲区,一般来说tcp的缓冲区是1M多,tcp的缓冲区是动态变化的,用户是不清楚的,32K很小,但用户也不敢去分配1M去充分使用内核的tcp缓冲区,但是内核是明明白白的,内核自己来发送的时候会用最大化它发送的长度,比如说每次拷贝1.4M,这样大量减少切换次数.这样就会快很多.用了0拷贝以后,性能可能能增加1倍.(动手测一下).man sendfile
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

10.相比堆,为什么栈上分配对象的速度更快?

原因:
(1)每个线程都有一个独立的8M(可设置)的栈空间,这块空间是线程独有的,底层库不需要对这块
资源加锁,为线程独有,没有锁就会快很多,大概快了多少,需要测试,老师有个课程?之后看看.
(2)已经预分配好了,每次只要移动一下就好了,但是堆上的内存需要自己去申请再分配.简单来说:
(1)底层未加锁;
(2)预分配内存.拓展:
栈的问题:
(1)生命周期有限;
(2)资源受限,深层次的递归调用很容易导致栈溢出.

【10道大厂必考性能优化题】陶辉老师相关推荐

  1. 【10道大厂必考的计算机网络问题】陶辉老师

    目录 1.请详细介绍一下TCP的三次握手协议,为什么要三次握手? 2.说说HTTP协议中缓存的处理流程?缓存的应用流程?与缓存相关的HTTP头部? 3.在地址栏键入URL后,网络世界发生了什么? 4. ...

  2. 10 道大厂面试必考的计算机网络问题-陶辉 极客时间

    大厂中更多会考察你的长板. 在大厂中要学会求助 1.TCP的三次握手机制,为什么要三次? 为什么需要握手? 需要同步序列号,当然也有MSS(最大报文段长度),滑动窗口. 为什么是3次? 正常想法应该是 ...

  3. 2022年最新的Android面试大厂必考174题(附带详细答案)

    前言 互联网行业竞争也越来残酷,我们工程师只有不断地学习,提升自己的能力才更保障你拿到更好的薪水,进入理想的企业(阿里.字节.腾讯.美团 等等-) 但目前很多人出现了一系列的疑惑问题就是: 以你目前的 ...

  4. 6 道 BATJ 必考的 Java 面试题

    转载自   6 道 BATJ 必考的 Java 面试题 题目一 请对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别? 考点分析: 分析 Exception 和 Error ...

  5. (一)梳理前端知识体系,搞定大厂必考面试题

    梳理前端知识体系,搞定大厂必考面试题 常见面试题 JS基础知识 变量类型和计算 原型和原型链 作用域和闭包 异步和单线程 运行环境 HTTP协议 总结 常见面试题 JS基础知识 变量类型和计算 typ ...

  6. 10道python面试题,每题10分,你能的多少分!(内附python教程)

    image.png 1.一行代码实现1–100之和 10道python面试题,每题10分,你能的多少分! 2.简述面向对象中new和init区别 init是初始化方法,创建对象后,就立刻被默认调用了, ...

  7. 最全Java面试208题,涵盖大厂必考范围!强烈建议收藏~

    这些题目是去百度.小米.乐视.美团.58.猎豹.360.新浪.搜狐等一线互联网公司面试被问到的题目,熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率. 一.java基础面试知识点 java中= ...

  8. 175 道面试必考 Go 语言题目详细解答

    随着2010年代初云计算的兴起,这一转变掀起了浪潮.各大互联网巨头在技术战略层面,都试图把握此次潮流,举起了云计算的大旗. 随着云计算时代愈演愈烈,Go 语言的应用也越来越广泛,已然成为首选编程语言. ...

  9. 10种简单的Java性能优化

    是否正打算优化hashCode()方法?是否想要绕开正则表达式?Lukas Eder介绍了很多简单方便的性能优化小贴士以及扩展程序性能的技巧. 最近"全网域(Web Scale)" ...

最新文章

  1. 图像边缘检测--OpenCV之cvCanny函数
  2. 汪卫华院士:无序中找有序 复杂中寻规律
  3. KubeCon 北美前瞻|在 2020 最后,容器领域有哪些值得你关注的话题?
  4. 解决MyBatis的报错 There is no getter for property named ‘*‘ in ‘class java.lang.String‘
  5. SpringMVC常用配置-添加静态资源处理器-针对SpringMVC中静态资源无法访问的问题...
  6. BOOST 线程完全攻略 - 结束语
  7. oracle 邻接模型,【原创】MySQL 模拟Oracle邻接模型树形处理
  8. 【HTML/CSS】margin塌陷和合并问题
  9. 游戏玩家场景高清桌面壁纸都是什么样的?
  10. php数据库find(),db_find()
  11. 从零开始学习python编程-和尧名大叔一起从0开始学Python编程-循环
  12. RichTextBox中插入图片
  13. C++--第1课 - C到C++的升级
  14. php过滤多空格_php如何去除多余空格
  15. 海康/大华实现web直播和回放,也可以直接对接摄像头
  16. linux虚拟机系统下安装jdk
  17. 搜狗浏览器怎么翻译英文网页
  18. 从语言之争到年龄焦虑
  19. tecplot有效数字位数
  20. 如何规避Adobe Flash Player中重橙网络的广告弹窗

热门文章

  1. 地理信息系统概论复习重点
  2. 红米Note-4G双卡移动版线刷兼救砖_解账户锁_纯净刷机包_教程
  3. 什么是CDN,内容分发网络学习
  4. 松下要造懒人必备智能家居:用平板指挥微波炉
  5. 火车头抓取阿里巴巴内容页
  6. Anaconda和pycharm
  7. 用途:不挂断地运行命令。
  8. excel中整列填充数据方法
  9. 微软雅黑html中怎么写,网页中使用微软雅黑字体(css调用微软雅黑)
  10. P4766 Outer space invaders