腾讯实习面筋

腾讯的面筋网上很多,这里整理了部分面筋,如下:

面筋1

1.你如何处理线程池中线程的数量

在这里就说一下“如何设定线程池中线程的数目?”

线程池中线程的数目是跟线程池所要处理的任务性质有关的

1.任务的性质:CPU密集型任务、IO密集型任务、混合型任务。
2.任务的优先级:高、中、低。
3.任务的执行时间:长、中、短。
4.任务的依赖性:是否依赖其他系统资源,如数据库连接等。

性质不同的任务可以交给不同规模的线程池执行。

针对不同的任务性质而言:

CPU密集型任务应配置尽可能小的线程,如配置CPU个数+1的线程数,IO密集型任务应配置尽可能多的线程,因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,如配置两倍CPU个数+1,而对于混合型的任务,如果可以拆分,拆分成IO密集型和CPU密集型分别处理,前提是两者运行的时间是差不多的,如果处理时间相差很大,则没必要拆分了。

任务对其他系统资源有依赖:

如某个任务依赖数据库的连接返回的结果,这时候等待的时间越长,则CPU空闲的时间越长,那么线程数量应设置得越大,才能更好的利用CPU。
线程等待时间所占比例越高,这样的话CPU空闲时间比较多,为了能够更好的利用CPU,需要较多线程。

如果线程CPU时间所占比例越高,说明CPU比较繁忙,此时需要越少线程
另外,如果线程数量过多,线程之间的切换也会带来开销。

是否使用线程池就一定比使用单线程高效呢?
答案是否定的,比如Redis就是单线程的,但它却非常高效,基本操作都能达到十万量级/s。从线程这个角度来看,部分原因在于:多线程带来线程上下文切换开销,单线程就没有这种开销。

讲讲epoll和select的区别

1.select,轮询设备描述符,判断是否准备好,用一个结构体来保存所有的设备描述符,设备描述符的个数是有限制的,属于同步的阻塞IO操作范畴,只支持水平触发。

2.epoll,也是轮询设备描述符,和select不同的是,epoll有一个队列,将那些以及准备好的设备描述符加入到队列中,不需要轮询所有描述符

第二点,epoll只用一开始将监控的描述符加入到队列中,而不用每次将描述符从用户态拷贝到内核态。select则需要每次拷贝。

你为什么选择边缘触发

边缘触发,类似非阻塞的操作,一旦设备描述符就绪了,就去通知用户来操作,只会通知一次,用户如果没有操作,则不会进行下一次通知。
水平触发,是所有select,poll, epoll都会支持的操作,会不停的通知用户操作。

选择边缘触发的好处是,

1.对于监听的sockfd,最好使用水平触发模式,边缘触发模式会导致高并发情况下,有的客户端会连接不上。如果非要使用边缘触发,网上有的方案是用while来循环accept()。

2.对于读写的connfd,水平触发模式下,阻塞和非阻塞效果都一样,不过为了防止特殊情况,还是建议设置非阻塞。

3.对于读写的connfd,边缘触发模式下,必须使用非阻塞IO,并要一次性全部读写完数据。

cpp多态

1.一个函数,运行的时候可以执行多种状态
2.虚函数底层——虚函数表
3.虚基类的使用需要注意什么——注意接口,纯虚函数不能实例化

4.hashtable 是如何处理 hash冲突的
开放式寻址法和开链法。stl的hashtable中使用的是开链法

redis的相关内容

实现一个分配锁的服务器
客户端如何请求
客户端 服务器通信死锁如何处理
服务器死机如何处理
多台服务器的健全设计方案
————————————————————————————————————————————

面筋2

(1) 进程线程了解吗?

了解,进程是操作系统资源分配的最小单元,线程是轻量级的进程,是处理器cpu的分配最小单元,线程的出现是为了在cpu上更好的并发执行。多个线程可以在多个cpu核行运行。

(2) 线程里面有什么是独立的?

线程独立的部分是保留运行的最基本的信息,例如程序计数器,一组寄存器和栈。

线程共享的环境包括:

1.进程代码段
2.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)
3.进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。

线程独立的资源包括:

1.线程ID
每个线程都有自己的线程ID,这个ID在本进程中是唯一的。进程用此来标识线程。

2.寄存器组的值
由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线程切换到另一个线程上 时,必须将原有的线程的寄存器集合的状态保存,以便将来该线程在被重新切换到时能得以恢复。

3.线程的堆栈
堆栈是保证线程独立运行所必须的。线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程必须拥有自己的
函数堆栈, 使得函数调用可以正常执行,不受其他线程的影响。

4.错误返回码
由于同一个进程中有很多个线程在同时运行,可能某个线程进行系统调用后设置了errno值,而在该 线程还没有处理这个错误,
另外一个线程就在此时被调度器投入运行,这样错误值就有可能被修改。所以,不同的线程应该拥有自己的错误返回码变量。

5.线程的信号屏蔽码
由于每个线程所感兴趣的信号不同,所以线程的信号屏蔽码应该由线程自己管理。但所有的线程都 共享同样的信号处理器。

6.线程的优先级
由于线程需要像进程那样能够被调度,那么就必须要有可供调度使用的参数,这个参数就是线程的优先级。

(3) 一个进程一定要有一个线程吗?没有线程的进程是什么?

不用,没有线程的进程叫做僵尸进程,等待资源被回收。

(4) 协程是什么?

协程是轻量级的线程,它和线程相对应,但是区别是它支持类似中断的操作,两个协程之间可以互相中断去执行,即协程之间的切换开销非常小,效率高。

相比于线程,线程访问同一个资源可能要进行加锁切换操作,比较多。

协程的特点在于是一个线程执行,那和多线程比,协程有何优势?
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

(5) 同步和互斥是怎么做的?

同步和互斥是针对线程来说的

线程的同步指的是多个线程按照一定的顺序去执行,例如生产者和消费者,生产者线程先执行,执行完了之后消费者线程才能执行。

—线程的互斥,指的是多个线程访问临界资源,一个线程访问一个资源,另外一个资源不能访问这个资源。

线程的同步可以用,信号量PV操作
线程的互斥可以用锁来完成。

(6) 线程间的同步和互斥是怎么做的?

和上一题是一样的。

(7) 守护进程和僵尸进程,孤儿进程有什么了解?

守护进程是该进程出现之后就一直存在,轮询操作某一事件。

孤儿进程又称为僵尸进程,由于子进程处理完成后,父进程灭有接收通知回收子进程,则会产生孤儿进程。

(8) 系统出现僵尸进程,为什么产生和怎么解决?

阻塞的方法,调用waitpid函数监控子进程,子进程结束后,可以直接回收资源
非阻塞的情况,调用handchild函数,监控sigchld信号,通过信号处理函数去处理。

(9) 软连接和硬连接了解吗?

软连接,一个文件存放物理节点一个inode索引,另一个文件存放一个路径的索引,索引到另外一个节点上。
硬节点,两个innode到同一个物理文件。

(10) 硬连接和软连接删了,原对象会如何?

硬连接删除,另外一个节点不受影响
软连接删除,若删除原结点,则另外一个快捷方式的节点则不能访问。

(11) 硬连接和软连接的底层原理?

一个保存实际索引,一个保存路径。

(12) Inode是什么?

文件索引

(13) 强类型和弱类型,静态类型动态类型是什么?

强类型指的是不能隐式转换的语言java
弱类型指的是可以隐式装换的语言,例如c/c++
静态类型指的是编译的时候就确定了对象类型,不能改变。java,c/c++
动态类型指的编译的时候没有确定类型,python

强类型:偏向于不容忍隐式类型转换。譬如说haskell的int就不能变成double
弱类型:偏向于容忍隐式类型转换。譬如说C语言的int可以变成double
静态类型:编译的时候就知道每一个变量的类型检查,因为类型错误而不能做的事情是语法错误。
动态类型:编译的时候不知道每一个变量的类型,运行的时候才检查类型
譬如说你不能对一个数字a写a[10]当数组用。

(14) TCP/UDP的了解?

tcp面向流,可靠传输,拥塞流量控制。

(15) Tcp和udp的使用场景

可靠传输,对速度没有要求,用tcp
不可靠传输,速度很快的场景,用udp

(16) Tcp粘包

—因为TCP是面向流的,所以存在分片的现象。TCP中发送有一个缓冲区,缓冲区有固定大小,如果两个包刚好满足这个缓存大小,那么就正常接收,但是其中一个包和另外一个包一部分一起发过去,就发生了粘包过程,当然还有可能是分包情况,同一个包,两次才能接收到。

产生粘包的原因很多:可能是数据缓存给了太大,可能受到MTU的影响

————————————————————————————————————————————

理解(16)一下,TCP分段和IP分页的区别与联系

写在前面:
分组能够发生在运输层和网络层。运输层中的TCP会分段,网络层中的IP会分片。IP层的分片很多其它的是为运输层的UDP服务的,因为TCP自己会避免IP的分片,所以使用TCP传输在IP层都不会发生分片的现象。

我们在学习TCP/IP协议时都知道。TCP报文段假设非常长的话,会在发送时发生分段。在接受时进行重组,相同IP数据报在长度超过一定值时也会发生分片,在接收端再将分片重组。

我们先来看两个与TCP报文段分段和IP数据报分片密切相关的概念。

MYU(最大传输单元)

MTU前面已经说过了,是链路层中的网络对数据帧的一个限制,依旧以以太网为例。MTU为1500个字节。一个IP数据报在以太网中 传输,假设它的长度大于该MTU值,就要进行分片传输,使得每片数据报的长度小于MTU。

分片传输的IP数据报不一定按序到达。但IP首部中的信息能让这些数据报片按序组装。IP数据报的分片与重组是在网络层进完毕的。

MSS(最大分段大小)

MSS是TCP里的一个概念(首部的选项字段中)。MSS是TCP数据包每次可以传输的最大数据分段,TCP报文段的长度大于MSS时,要进行分段传输。

TCP协议在建立连接的时候通常要协商两方的MSS值,每一方都实用于通告它期望接收的MSS选项(MSS选项仅仅出如今SYN报文段中,即TCP三次握手的前两次)。MSS的值一般为MTU值减去两个首部大小(须要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以假设用链路层以太网。MSS的值往往为1460。而Internet上标准的MTU(最小的MTU,链路层网络为x2.5时)为576,那么假设不设置,则MSS的默认值就为536个字节。非常多时候,MSS的值最好取512的倍数。TCP报文段的分段与重组是在运输层完毕的。

到了这里有一个问题自然就明了了,TCP分段的原因是MSS,IP分片的原因是MTU,因为一直有MSS<=MTU。非常明显,分段后的每一段TCP报文段再加上IP首部后的长度不可能超过MTU,因此也就不须要在网络层进行IP分片了。因此TCP报文段非常少会发生IP分片的情况。

再来看UDP数据报,因为UDP数据报不会自己进行分段,因此当长度超过了MTU时,会在网络层进行IP分片。相同。ICMP(在网络层中)相同会出现IP分片情况。

总结:UDP不会分段,就由IP来分。

TCP会分段。当然就不用IP来分了!

另外。IP数据报分片后,仅仅有第一片带有UDP首部或ICMP首部,其余的分片仅仅有IP头部,到了端点后依据IP头部中的信息再网络层进行重组。而TCP报文段的每一个分段中都有TCP首部,到了端点后依据TCP首部的信息在传输层进行重组。

IP数据报分片后,仅仅有到达目的地后才进行重组,而不是向其它网络协议,在下一站就要进行重组。

最后一点,对IP分片的数据报来说。即使仅仅丢失一片数据也要又一次传整个数据报(既然有重传。说明运输层使用的是具有重传功能的协议,如TCP协议)。

这是由于IP层本身没有超时重传机制------由更高层(比方TCP)来负责超时和重传。当来自TCP报文段的某一段(在IP数据报的某一片中)丢失后,TCP在超时后会重发整个TCP报文段,该报文段相应于一份IP数据报(可能有多个IP分片)。没有办法仅仅重传数据报中的一个数据分片。

在IP层分片时,仅仅有第一个分片存在运输层协议头部,其余分片都不包括运输层协议的首部,这一点非常重要。然后TCP的分段,每个分段都包括TCP首部信息,。
再有就是IP分片时到达目的地之后再进行重组的,IP层的重组是发生在目的地的IP层,TCP的重组是发生在目的地的传输层中。
———————————————————————————————————————————————

(17) Tcp的time_wait (到这里我觉得面试官面不下去了)

timewait指的是2msl的时间,保证四次挥手的时候服务器没有接收到ack,重发关闭请求的时候可以收到。

(18) http1.0和1.1有什么区别——记住主要的两点区别

http1.1一个有头部,可以确定给不同的服务器分发上,一个是1.1是长接连的,只用一次tcp连接
1.0不包含头部,是短连接的,每次都给重新建立tcp连接

(19) https协议?原理?端到端中间的过程。

http加上s,安全的传输

(20) 对称加密和非对称加密?

对称加密,双方都有共同的私钥,由私钥对数据加密
非对称加密,一个公钥和私钥,公钥加密,私钥解密

(21) Cookies和session的关系

(22) Cookies的最大保存时间

二者作用:解决HTTP协议无状态的缺陷,在客户端/服务器端保存会话状态。

创建Session过程:

检查客户端请求中是否包含一个session标识(session id)
● 若包含,则说明之前已经为此客户端创建过session。服务器按照此session id检索出session
● 若不包含,则为此客户端创建一个session,并生成一个session id。此session id将作为响应返回给客户端保存。(使用Cookie保存)
若Cookie被禁止,必须有其他机制能够把session id回传给服务器

回传session id至服务器:

● URL重写:把session id直接附加在URL路径后面
● 隐藏表单字段
Cookie和Session的区别:
Cookie中只能保存ASCII字符串,Session中可以保存任意类型的数据,甚至Java Bean乃至任何Java类、对象等
● 隐私策略不同。Cookie存储在客户端,对客户端是可见的,可被客户端窥探、复制、修改。而Session存储在服务器上,不存在敏感信息泄露的风险
● 有效期不同。Cookie的过期时间可以被设置很长。Session依赖于名为JSESSIONI的Cookie,其过期时间默认为-1,只要关闭了浏览器窗口,该Session就会过期,因此Session不能完成信息永久有效。如果Session的超时时间过长,服务器累计的Session就会越多,越容易导致内存溢出。
● 服务器压力不同。每个用户都会产生一个session,如果并发访问的用户过多,就会产生非常多的session,耗费大量的内存。因此,诸如Google、Baidu这样的网站,不太可能运用Session来追踪客户会话。
● 浏览器支持不同。Cookie运行在浏览器端,若浏览器不支持Cookie,需要运用Session和URL地址重写。
● 跨域支持不同。Cookie支持跨域访问(设置domain属性实现跨子域),Session不支持跨域访问

(23) Mysql索引的原理,底层是怎么存的?

在大量查找的数据库中,可以建立索引加快查找,
分为聚集索引和非聚集索引,聚集索引是b+树,叶子节点为索引的数据,非聚集索引叶子节点为指针,指向数据。

(24) 主键和唯一键有什么区别?

一个表中只能有一个主键,可以有多个唯一键
主键不能为空,唯一键可以为空

(25) Varchar和char的区别?

varchar长度是可以动态改变的,char是固定的长度

(26) UTF-8下面varchar能占多少字符?GBK呢?

1.一个汉字占多少长度与编码有关:
UTF-8:一个汉字=3个字节
GBK:一个汉字=2个字节

2.在MySQL中 varchar(n)和char(n)表示n个字符,无论汉字和英文,Mysql都能存入n个字符,仅是实际字节长度有所区别

即 MySQL 并不会对超过长度的字符报错,而是直接截断了. 并且 char(2) 和 varchar(2) 都能存储 2个汉字,或者是两个英文字符.

3.MySQL 的 char(n) 和varchar(n) 可以直接存储 n 个汉字. 而不是 n/3或者 n/2 个,mysql 屏蔽了具体的存储细节,而直接以实际字符的个数来决定char存储的个数

(27) 说下你知道的排序,比较一下他们的优缺点,复杂度和应用场景

————————————————————————————————————————————

(28)全局变量和static变量的区别.

如果在两个.h文件中声明两个同名变量会怎么样? 如果使用extern 如果没有使用

全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。

会覆盖,使用extern,则两个变量是同一个变量。
————————————————————————————————————————————

面筋3

1.C++ struct和class的区别
2.虚函数相关(多态如何实现,可以把构造函数声明成虚函数吗)
3.编译原理的一些问题
4.struct和class的字节对齐和原因
5.C++堆和栈的区别
6.常用的排序算法
7.有序数组二分查找的时间复杂度
8.二叉树的前序遍历、中序遍历、后序遍历
9.TCP/IP分层
10.TCP协议和UDP协议的区别
11.TCP三次握手
12.TIME_WAIT状态
13.浏览器输入www.qq.com,从TCP/IP分层说全过程,可能会在哪些过程出问题
14.TCP(流式协议)包大小的控制(不太懂意思)
15.多线程和多进程的优缺点
16.进程和线程通信方式
17.一个进程创建共享内存,退出还存在吗
18.场景题:服务突然启动不了怎么调试
19.EPOLL ET模式和LT模式
20.多个线程同一socket同时读写问题(EPOLL_ONESHOT)
21.智力题:64匹马,8条跑道,不允许计时,只计名次,决出前四名充分必要条件要多少次
22.Top m问题(m不是常数,数据量大)
23.求逆序数对
24.数据库索引的结构
25.map、unordered_map的实现原理、时间复杂度
26.红黑树和平衡二叉树

面筋4

1、自我介绍
2、数据库使用的怎么样等等
3、数据结构

● B+树
● 红黑树
● 图的最短路径
● 等等

4、网络编程

● 高并发与异步的服务器怎么设计
● epoll后的套接字怎么存
● 等等

5、项目
————————————————————————————————————————————

面筋5

epoll, nginx的IO模型, select区别

select区别:

同步的轮询io请求,select中提供一个fd_set的数据结构,这个数据结构实际上是long型的数组,每个数组的元素都是一个打开的文件句柄。

当调用select的时候,内核论文这个数据结构,如果有句柄准备好了,修改这个数组中的句柄,由此来通知select的进程判断文件是否准准备好。

缺点:

1.将所有的文件句柄首先由用户态拷贝到内核态的数组中。
2.每次遍历所有的句柄

3.一般采用的是水平触发,如果某个描述符完成了通知用户,用户没有取,会不停的去通知。
4.每次都需要对设备描述符清零,并重新置入新的设备描述符

poll:

和select类型,但是使用的是poll_fd的描述符,而不是fd-set,其他的操作流程和select类似。

不同点:

1.监视的描述符的个数是没有上限的
2.每次检测一遍poll_fd的描述符集合后,不会对其清零,select会对其清零

epoll:

优化版的poll,将所有被内核通知唤醒的设备描述符放入到一个等待队列中,不需要遍历所有的文件描述符集合,同时除了水平触发之外,还提供边缘触发,即通知一次之后就不在通知了。
在这里插入图片描述

面筋6

C++

1 STL实现

比如vector map
vector是容器,底层用红黑树完成
map,如果是有序map,由红黑树完成,无序的map由hashtable完成

2 sizeof(*), sizeof([]) 编译期确定

sizeof是一个操作符,类似±这样的操作符,它返回对象或者类型所占的字节数。

  1. sizeof( object ); // sizeof( 对象 );
  2. sizeof( type_name ); // sizeof( 类型 );
  3. sizeof object; // sizeof 对象;

对于sizeof(*)指针的sizeof是一个指针,指针存放的是地址,那么就是机器的地址数占的字节。
对于sizeof([]) 表示sizeof一个数组,等于数组所占的字节数

char a1[] = "abc";
int a2[3];
sizeof( a1 ); // 结果为4,字符串末尾还存在一个NULL终止符
sizeof( a2 ); // 结果为3*4=12(依赖于int)
3 const实现

const的实现,函数和变量

4 多态实现
5 malloc实现,可能是伙伴算法

两级malloc,第一级malloca就是常见的分配大块内存
第二级是会产生一个由链表组成的,包含16个不同大小的内存块,当取的小内存块的时候,从第二块上取。

在这里插入图片描述
当需要的内存块大于128byte的时候,用第一级配置器,否则用第二层配置器。

OS

1 线程进程区别 线程私有哪些数据

主要有进程的代码段,数据段,同时有自己的堆栈,自己的进程号,自己的优先级等一些寄存器。

2 进程内存布局

.text,——代码区
data——数据区
bss——未初始化的变量区,没有真实的存放数据,只是存放了没有初始化的静态全局变量的大小
heap, stack

3 动态链接和静态链接区别

一个是编译的时候确定,一个是运行的时候确定。

4 静态链接过程 细节?
5 文件系统 inode

文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。

操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。

文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。

每一个文件都有对应的inode,里面包含了与该文件有关的一些信息

网络

1 tcp 三次握手and why, 4次挥手
2 拥塞窗口 慢启动
3 tcp udp 区别,他提到到达顺序

数据库

1 索引结构,why
2 引擎
3 what is 事务

算法

1.n个数 只有一个出现1次,其他的出现2次

异或的方法

2 top k 大, 快排partition() 时间复杂度 O(n) ?

——快排,每次判断快排之后的数据量的大小,属于哪个,区间段,当区间段是左边的k个区间段,那么左边的k个就是topk.最好的情况是第一次选取的数据就是k,最差的情况数据是最后一个。

3 子数组最大的和 DP

https://leetcode.com/problems/maximum-subarray/description/

4 洗牌算法

洗牌算法
我们都多多少少学过几种排序,常见的几种排序大类有插入排序,希尔排序,选择排序,交换排序。然而,洗牌算法的目的是将有序的数组进行打乱

一般的洗牌算法

1、利用一个队列
2、每次从数组中,随机找到一个数;

若该数没有被选择过,那么就将它放入队列中;如果被选择过,就重新随机
毋庸置疑,这个算法是可以满足洗牌的要求的然而呢,让我们看一下该算法时间复杂度

每次选择一个数,可能存在已经选择过的情况
所以该算法的时间复杂度是O(N* N)
并且又多用到了一个队列,空间复杂度也不是很好

更优的洗牌算法

该算法类似于插入排序
从数组的最后一个数(下标为i)开始,进行随机取余(除数为i+1,确保下标不过界),将得到的下标对应的元素和最后一个数交换。将最后一个数不在视为数组中的元素,继续循环直到只剩下第一个元素为止。
在这里插入图片描述

5 多机器 top k

智力题

老鼠毒药 利用二进制
问题:

现有一千瓶药水,其中九百九十九瓶是完全一样的,只有一瓶里面是毒药,但是外观上分辨不出来。毒药给小白鼠喝了后,一星期后这只小白鼠会突然死亡,但之前一点症状也没有。现需要在一星期后找出哪瓶是毒药,问至少需要几只小白鼠?

这是一个求最优解的问题。这个问题需要把一个老鼠能使用的信息用到极致,即能达到最优解。

问题解析:

巧妙利用二进制编号是这道问题的关键
1.给每个瓶子用二进制编号,总共有1000瓶,2的10次方等于1024,只需用十位二进制就可表示所有的瓶子,每一位依次用w1、w2、…w10表示。

2.给每个老鼠编号,c1、c2、…c10分别给十只老鼠编号,

编号c1的老鼠只喝w1位上为1的药水瓶,编号c2的老鼠只喝w2位上为1的药水瓶,依次类推。
即c1号老鼠和掉的药为,1000000001,1000000010,1000000011…
最后看哪些老鼠死掉,例如c10、c8、c7、c4、c3、c1编号的老鼠死掉,那么有毒药水的编号就是10 1100 1101
如果所有老鼠都没意死,那么说明毒药的二进制编号为0000000000。
————————————————————————————————————————————

面筋5

1.vector和list的区别的,应用,越详细越好。

vector容器,具有随机访问的特性,而且数据是连续存储的,其中增加节点较多的时候,超过第一次开辟的空间时,会降低效率,重新开辟新的区间,在进行拷贝操作。
应用,主要是在支持随机访问的情况,但是插入删除较少

list容器,不具有随机访问的特性,而且数据的存储空间不是连续的,是链表的实现,所以访问元素只能通过链表的遍历O(n)的效率,但是可以高效的插入和删除
应用,主要是应用插入删除较多的情况,随机读取较少的情况中。例如LRU算法
在这里插入图片描述
在这里插入图片描述

2.C++ STL 内存优化

主要是使用到两层内存的优化策略,第一级是大片内存的分配,第二级维护了一个16个指针的链表,每个指针指向了8~128MB的内存块。

两级策略是,当需要分配的内存较小的时候,选择第二级去分配,当需要分配的内存超过128MB的时候,选择第一级分配器去直接分配。

4.给你1MB的内存,你们怎么设计, 才能使其利用率最高,产生的碎片最少

采用分页法,1MB的内存,每4KB为单位进行,设置一个映射表,非连续性分配。
最坏的情况,只有一个4KB产生碎片。

5.用户态到内核态的转化原理。(答起了部分)

操作系统为了更好的隔离系统和应用,才引用了用户态和内核态,用户态完成用户功能的实现,设计进程,内存,文件系统等问题交由内核态来完成,这样做的目的更加安全,所以存在有用户态向内核态陷入的过程。

最常见的用户态到内核态的转换是系统调用,例如系统调用一个读写函数,这个函数调用文件系统的api,这个时候陷入内核态,内核完成对设备的打开,返回设备的句柄,对数据的读写。

6.linux内核中的Timer 定时器机制。(不知道)

没用过,但是知道是可以设置一个时间,在未来的某个时间点,时间到达执行某种功能操作或者中断。

7.TCP的三次握手四次挥手 ,拥塞,流量,可靠性的原理。

可靠性原理分两个部分,一个是握手的可靠性,一个是携带有校验码。

8.TIME_WAIT状态分析。

timewait发生在第二次挥手过程中,当服务器端上层完成了任务,下发关闭的请求时,这个时候服务器端向客户端发送挥手,客户端收到了挥手,这个时候进入了timewait状态,这个状态有2MSL的时间,目的是为了保证回确认服务器没收到,可以重传挥手信号,这个时间内可以再次收到。
在这里插入图片描述

9.C++ 类成员初始化,为什么按顺序顺序, 构造函数的调用和 代码扩展,还有初始化列表?

类成员的初始化严格按照声明的顺序进行初始化
构造函数的调用的时候,进行初始化,最好需要按照类的成员声明的顺序进行。

10.类成员初始化的方式。

一种是直接初始化,以()进行的,叫做列表初始化,列表初始化是给数据成员分配内存空间时就进行初始化,就是说分配一个数据成员只要冒号后有此数据成员的赋值表达式(此表达式必须是括号赋值表达式),那么分配了内存空间后在进入函数体之前给数据成员赋值,就是说初始化这个数据成员此时函数体还未执行。
在这里插入图片描述
还有一种是赋值初始化,这种初始化是成员已经被分配空间之后,在进行拷贝赋值操作呢进行初始化:这种初始化,效率低下,因为使用了先分配的数据空间,然后进行了拷贝,如果是类似容器这种的拷贝可能会很大的降低时间效率。
在这里插入图片描述

11.const成员函数的理解和应用。

const的成员函数,是指对那些不修改成员变量的函数进行定义,这样的好处是让编译器直接了当的知道用户的目的,这样当用户非法改变成员变量的时候,就会报错。

intGetCount(void) const; // const 成员函数

a.在类中被const声明的成员函数只能访问const成员函数,而非const函数可以访问任意的成员函数,包括const成员函数…

b.在类中被const声明的成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.

12.50 亿个整数中, 找一个确定的数? 有内存限制, 并且无序

要使用bitmap,或者是bloomfilter
将这50亿的数目进行bitmap的设置,有的就设置为 1,然后检查这个数在bitmap是否为1

面筋6

1.操作系统进程通信
进程通信IPC的五中方式:管道,命名管道,共享内存,消息队列,信号量,套接字。

2.Const
不可以修改的修饰符。

3.Tcp3次握手
客户端第一次握手,表明自己可以发送
服务器端接收,发送确认握手,表示自己可以接收并发送
客户端接收,并发送确认。

4.字节对齐
高位字节能整除低位字节
最后的内存是最大字节数的整数倍

5.然后strcpy忘记判断dst为NULL。
在这里插入图片描述
考虑到内存重叠的问题
在这里插入图片描述

6.给你一段逻辑连续的内存,你怎么设计(全程怼我怎么保证充分利用空间和动态分配)
采用不连续的页映射的方法。

7.讲讲常用排序的优缺点,应用场景
时间复杂度低的是快排,归并,堆排,
在这里插入图片描述

8.在上面那个我说道了拥塞控制,就开始问 TCP 拥塞控制机制
慢启动,拥塞阈值控制,快重传,快恢复

9.既然你的设计就是类似 TCP(我用的 UDP 来设计),为什么不用 TCP
udp传的速度快,可能丢包,但是对于视频来说,piq帧可以恢复。

10.逻辑题:6个赛道,36匹马,找出 top 1(如果是 top 6 呢)
7次(6+1)

面筋7

1、TCP、UDP的区别,网络电话应该用什么协议,为什么

网络电话应该用tcp,因为要保证可靠传输

2、最小生成树算法

最小生成树的问题主要有两个经典的算法,Kruskal算法和Prim算法,首先选择最小的边进行,然后根据这个边进贪心算法,每次走的都选择最小的权重走,但是不能形成环路。

3、广度优先搜索和深度优先搜寻

拿一个树来看,深度优先就是遍历到叶子节点,在回溯到上一层的子节点、
广度优先就是不同的遍历子节点,直到叶子节点

4、C++的析构函数为什么一般为虚函数

子类先析构,父类在析构

5、进程间通讯

6、线程同步,有几种方法

常见的是信号量和互斥锁

面筋8

2.讲下TCP通信
3.进程和线程区别
4.进程通信几种方式,然后讲下共享内存原理和具体实现
通过内存映射到同一个文件,然后用文件进行共享,如果有文件了就类似了管道了

5.LRU缓存,问在特定场景比如缓存不同文件的数据的话,怎么缓存
6.求两条单向链表第一个公共结点
7.求二叉树的高度
8.求数组非连续的最长递增子序列的长度

面筋9

1.引用和指针的区别。
指针是一个对象,可以拷贝不初始化
引用只是一个别名,再初始化的时候就绑定了对象,而且一直不会变

2.定义和声明的区别。
声明只是告诉编译器,这个变量的名字已经存在的了,别的地方不能再用了。
定义是为一个对象分配内存

3.内存溢出和内存泄漏。
溢出,数组的越界
泄漏,malloc之后没有回收

4.进程和线程的区别。 调度方面,并发性,拥有资源,系统开销。
5.进程间通信。 共享内存,消息传递(直接,间接),管道通信,socket。。。
6.堆和栈的区别。根本没答上来

7.GET和POST的区别。 说了好多个,能想到的都说了
在这里插入图片描述

8.TCP三次握手的过程。 基础题目
9.select,epoll的区别。 原理,性能,限制都说了说
10.洗牌发牌算法。 说了两种办法
11.实现12306余票查询的关键数据结构与算法。当时就感觉凉了,耐着性子和面试官讨论,面试官引导我这个和座位有关,慢慢 写了个简单版的。

面筋10

● 介绍fork函数
一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

● 介绍time_wait状态
● 为什么tcp连接握手需要三次

● 介绍迭代器失效。push_back会导致迭代器失效吗。
会,不停的push_back,导致容器重新分配空间了,这个时候迭代器就失效了。

● 红黑树的特征,介绍
一种平衡二叉树,相比于avltree来说没有那么严格,但是它使用的是红黑来限制树不会倾斜的太多,主要使用以下方法:

红黑树是一种二叉查找树,但在每个结点上增加了一个存储位表示结点的颜色,可以是RED或者BLACK。通过对任何一条从根到叶子的路径上各个着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。

主要满足:

(1)每个结点或是红色,或是黑色。
(2)根结点是黑色。
(3)每个叶子结点(NIL)是黑色。
(4)如果有一个结点是红色,则它的两个儿子都是黑色。
(5)对每个结点,从该结点到其孙子结点的所有路径上包含相同数目的黑色结点。

● 哈希冲突的解决方法。
开放式寻址法和开链法

● 进程和线程的区别
● 你都使用什么线程模型
生产者和消费者

● 介绍协程
一种轻量级的线程,和线程不一样,没有锁的机制,类似于中断,不同协程之间可以中断的打断去执行。

● 介绍快排算法
● 什么是稳定性排序,快排是稳定性的吗,为什么
快排不稳定,因为快排在交换的时候,相同的数据可能多次交换导致数据位置互换。

● 快排算法最差情况推导公式
例如排序最小,如果是序列初始化就是最大的,这个时候不停的交换。

● 析构函数虚函数为什么
先析构子类,在析构父类。

● 构造函数为什么不能是虚函数
因为先父类的构造,才有子类的构造,父类没有构造完成的时候,子类是未初始化的状态,那么如果将构造函数定义为虚函数,虚函数在子类中会覆盖父类的虚函数,那么构造的时候调用子类的构造函数是一个未初始化的状态,显然是不行的。

● 打印在纸上的题目,考察:new [] 对象。static 成员。子类构造函数具体调用了啥。
new[]对象是一个数组,例如,int *p = new int[20],定义一个20个长度的int的数组,释放这个数组使用方法delete[] p;

静态成员可以被非静态或者静态成员函数访问,但是必须在结构体外部进行初始化。
子类的构造函数,构造的顺序是先构造基类,在构造子类成员变量,在构造子类。
子类的析构函数,析构的顺序是先析构子类,然后析构子类对应的父类,然后析构子类成员变量,在去析构父类。

● 拷贝构造函数与赋值函数的区别。等号在拷贝构造函数出现的时机。什么时候需要赋值函
数。深拷贝与浅拷贝。虚函数的调用时机。

拷贝构造函数是一种构造函数,是在对象构造的时候调用的,拷贝构造函数具体来说会出现在两个地方,一个是普通构造函数,使用另一个对象进行列表初始化,匹配到的是拷贝构造函数。另外一种是拷贝初始化,这种就是用到了=号,也是在初始化的图中,使用等于号进行拷贝初始化,这种也调用了拷贝初始化。

赋值函数,实际上是重载了赋值运算符,赋值自定义的对象之间,不发生在初始化阶段,和拷贝构造函数的区别在于一个在初始化阶段,一个不在。

为什么要涉及到深拷贝和浅拷贝的问题,就时自己要定义拷贝构造函数的意义,因为如果对象中包含有类似指针的对象,那么默认的构造函数就是一个浅拷贝,会直接拷贝指针,这样即有两个指针指向了同一个内存区域,那么会发生意想不到的错误,所以这个时候定义拷贝构造函数,及深拷贝,拷贝指正指向内存空间的所有元素。

虚函数时动态绑定的,根据绑定的对象的是基类还是子类,来确定调用的虚函数是哪个。

● 随机出一道纸上的题目。给定前序遍历ABC后序遍历CBA,求中序遍历是什么,画出来两种情况。
根是A,可以画出两种情况

● 有100个弹珠,双方轮流拿,每个人只能拿1~5个,无法拿的人输,必胜解法。
100/6=16…4
甲拿4个,之后保持拿6个,最后剩余6个,乙拿,最后肯定有剩余的就是甲拿,甲胜出。

● 函数指针和指针函数的区别。写个例子出来。
指针函数是指带指针的函数,即本质是一个函数,函数返回类型是某一类型的指针

int *f(x,y);

指向函数的指针,本质上是一个指针,只不过这个指针指向了函数

int (*f) (int x); /*声明一个函数指针 */
f=func(1; /* 将func函数的首地址赋给指针f */

● 索引是什么。多加索引一定会好吗?(索引这个承认了看面经,但是后一个问题自己想出来了)
不一定,索引是那些查找多,删减少的加索引,,如果删减也比较多的,增加索引会增加访问磁盘的开销空间、

面筋11

1.创建对象的方法

两种方式,一种是调用默认初始化的函数,在栈内创建对象
在这里插入图片描述
第二种是利用new,在堆中创建对象
在这里插入图片描述

2.序列化

使用先序遍历,递归调用左右,将节点值放到序列化的容器中即可。

3.线程池

当有很多任务需要采用线程执行的时候,而且有时可能会创建很多线程的时候,最好使用下线程池。不使用线程池的话,所创建的线程数无法控制,比如一下子创建了几百几千个线程,电脑一下子就崩溃了。创建销毁线程,消耗资源较多。

优点

1:提高效率 创建好一定数量的线程放在池中,等需要使用的时候就从池中拿一个,这要比需要的时候创建一个线程对象要快的多。

2:方便管理 可以编写线程池管理代码对池中的线程统一进行管理,比如说系统启动时由该程序创建100个线程,每当有请求的时候,就分配一个线程去工作, 如果刚好并发有101个请求,那多出的这一个请求可以排队等候,避免因无休止的创建线程导致系统崩溃

4.http状态码,http头

404 没有找到
301.已经转移
500内部服务器错误
200成功访问

5.证明一个数是2的n次方

n&(n-1)== 0

6.堆排序

建堆,交换头部和尾部,然后减小堆的大小,在此调整堆

8.八大排序特点

冒泡,选择,插入,快速,堆排序,归并排序,希尔排序,基数排序

9.链表的倒数第k个节点

两个指针,一个指针先走k步,另外一个指针再走

10.new/malloc的区别

一个是操作符,一个值库函数
一个构造,一个值分配内存
一个返回对象的类型指针,一个返回空

11.协议,什么是TCP与UDP,各有什么优缺点,各自适用于哪些场景,3分钟。

tcp可靠传输,3次握手,4次挥手,点对点的传输,包过大会出现分段的现象,对传输质量有要求的地方
udp不可靠传输,以报文来发送,传输速度快,最大包不超过16位,对传输速度有要求的地方。

12.操作系统,linux进程的内存地址空间划分,从低地址到高地址,代码段->数据段->BSS段->堆区->栈区。

操作系统在管理内存时,每个进程都有一个独立的进程地址空间,进程地址空间的地址为虚拟地址,对于32位操作系统,该虚拟地址空间为2^32=4GB。 进程在执行的时候,看到和使用的内存地址都是虚拟地址,而操作系统通过MMU部件将进程使用的虚拟地址转换为物理地址。

进程地址空间中分为各个不同的部分:

(1)由于系统内核中有些代码、数据是所有进程所公用的,所以所有进程的进程地址空间中有一个专门的区域存放公共的内核代码和数据,该区域内的内容相同,且该虚拟内存映射到同一个物理内存区域。
(2)进程在执行的时候,需要维护进程相关的数据结构,比如页表、task和mm结构、内核栈等,这些数据结构是进程独立的,各个进程之间可能不同。这些数据结构在进程虚拟地址空间中一个专门的区域中。
(3)进程在进行函数调用的时候,需要使用栈,于是进程地址空间中存在一个专门的虚拟内存区域维护用户栈。
(4)进程在进行动态内存分配的时候,需要使用堆,于是进程地址空间中存在一个专门的虚拟内存区域维护堆。
(5)==进程中未初始化的数据在 .bss 段 ==
(6)进程中初始化的数据在 .data 段
(7)进程代码在 .text 段
(8)进程执行的时候可能会调用共享库,在进程地址空间中有一个共享库的存储器映射区域,
这个是进程独立的,因为每个进程可能调用不同的共享库。

linux系统中进程的地址空间分布如下图所示,其中在32位系统中0-3GB为用户空间,3-4GB为内核空间
在这里插入图片描述

13.bss段的功能

先明确 BSS 段“存放”的是未初始化的全局变量与局部静态变量,此处指的存放是指为其预留空间(占位符)。但BSS段在磁盘上不是真的占用变量大小的空间,它仅是在该段中记录了所有未初始化全局变量与局部静态变量的大小总和,至于每个变量的大小则存储在符号表的size属性中。

即:BSS段内容:无内容,它将在段表中占一个段描述符,该段描述符的size属性将记录未初始化的全局变量与局部静态变量的大小总和
每个未初始化全局对象与静态对象的大小:存储在符号表的 size 属性中

2.BSS段在加载运行前的处理

当可执行文件加载运行前,会为BSS段中的变量分配足够的空间并全部自动清理(因此,才有未初始化的全局变量的值为0的说法)。

3.BSS段的作用

BSS段主要是为了节省可执行文件在磁盘上所占的空间,其仅仅记录变量所需的大小。对未初始化的大型数组的节省效率比较明显

面筋12

1、char *s1, const char *s2,删除s1中s2出现过的字符
2、删除单项链表中重复的节点 (1 2 2 3 3 9) -> (1 2 3 9)
3、求二叉树的深度
4、单链表判环
5、判断一个数是不是回文数
6、求一个数组的最长连续子序列

面筋13

1、网络了解吗?讲一讲TCP协议的三次握手,为什么要有三次?(紧张,说得不够清楚,答的不好)

2、了解Linux吗?epoll了解吗?
epoll的特点主要有4点:

1.只需要拷贝一次所有的设备描述符
2.为每个描述符设置一个回调函数,当设备就绪的时候回调函数自动将这个fd加入到就绪队列中,每次只用遍历就绪队列即可。
3.fd是没有上限的
4.支持边缘触发

3、手撕代码,根据前序,中序创建二叉树
剑指offer的原题

4、问了stl里面set和map怎么实现的,顺势说了红黑树的性质还有左右旋转
红黑树实现的

5、mallca/free与new/delete的区别
构造函数,返回值

6、宏定义和枚举的区别(没答上来,说了下宏定义)
宏定义是离散的,
枚举是连续数量有限制的集合

7、c++ 的多态,说了下虚函数
8、构造函数为啥不能定义为虚函数
9、析构函数为啥一般定义为虚函数

10、看我简历上写了熟悉一些算法,让我说一下kmp的实现(太久了,忘得差不多了)
next数组,匹配字符串的时候可以移动多个位置

11、socket编程中服务器端和客户端主要用到哪些函数
在这里插入图片描述

12、某个进程使用的端口 netstat -? | grep pid
内存的查看:free -m,top
磁盘IO的查看:iostat

面筋14

C++

static
vector map 实现
C++ 多态实现

算法

快排
树深度
10e 高效数字排序_bitmap

项目

udp tcp的区别
面对流,面对报文
可靠传输,不可靠传输

手撕代码,二叉树的遍历
快排

磁盘SSD内存延时

磁盘在ms级
SSD在微妙级us,具体来说SSD的读在70us,写在1ms,擦在5ms左右,参考的是hynix的数据手册
内存的访问延时在ns级,10ns~100ns之间

吞吐量的对比

磁盘100MB
SSD 500MB
PCIE ssd 1~10GB
内存 几十GB以上

面筋15

1,struct和class的区别

默认的访问权限不一样,class是private,struct是public

2,union和struct的区别

1.在存储多个成员信息时,编译器会自动给struct第个成员分配存储空间,struct 可以存储多个成员信息,而Union每个成员会用同一个存储空间,只能存储最后一个成员的信息。

2.都是由多个不同的数据类型成员组成,但在任何同一时刻,Union只存放了一个被先选中的成员,而结构体的所有成员都存在。

3.对于Union的不同成员赋值,将会对其他成员重写,原来成员的值就不存在了,而对于struct 的不同成员赋值 是互不影响的。

4.sizeof,union是最大成员,sruct是所有成员并且进行对齐

3,给一个struct分析占用多少内存

使用内存对齐的方式,后面的地址是前面地址的整数倍

4,如果不想一个类被继承应该怎么办

不能被继承?不能被继承?不能被继承?按照继承的理论知识分析,我们只要把类的构造函数设置为私有的,即可解决问题。

因为那样的话,子类就没有办法访问基类的构造函数,从而就阻止了进行子类构造对象的任务实现,也就达到了不可继承的目的。

但是,假设那样,这个类我们在其它地方怎么使用呢?那这样子给我们的利用也造成了一定的障碍。

好了。你是不是也想到了,定义静态方法,在方法内部实现一个对象,然后返回它的指针。
Ok?那怎么释放掉呢?再照样设计一个释放内存函数,问题就会迎刃而解
在这里插入图片描述

5,装饰器模式和单例模式,使用单例模式应该注意什么

6,TCP和UDP的区别和各自适用的场景

tcp主要用于可靠性高的地方
udp用于速度较快的地方

7,http协议

工作在应用层的协议,超文本传输协议,主要是客户通过这个协议去获取web服务器的相关文本内容。
分为http1.0和http1.1,两个区别,一个是长连接,一个是短连接,一个有头部一个没有

8,什么是死锁,怎么避免死锁

两个线程同时访问临界区,产生竞争关系,彼此都希望对方释放锁,形成循环等待。
加锁顺序,加锁时间,死锁检测,检测后修改锁的优先级,或者强制剥夺。
在这里插入图片描述

9,linux常用的命令

10,python迭代器和生成器的区别

11,什么是线程和进程,多线程和多进程通信方式

锁,信号量

12,什么是单向链表,如何判断两个单向链表是否相交,手写代码,并分析时间复杂度

13、网络:

3次握手4次挥手
操作系统:
进程线程区别
多线程
LRU算法,一致性hash,增加几个节点怎么做

kv数据,资源不限,怎么样最快存储
对于容量大的,内存完全不够的,需要使用kv存储引擎,内存存放kv,v表示值在硬盘上的位置,同时使用追加写,即每次只有一个文件是活跃的,其他事不活跃的

对于容量小的,可以直接放在内存,或者放在硬盘进行swap交换,可以批量刷入硬盘或者ssd中

面筋16

算法

1.如何判断两个单项链表是否相交
2.网络三次挥手
3.udp包最大有多大
4.说下select和epoll的区别
5.边缘触发和水平触发的区别
6.说出常见的linux的一些命令
7.查看一个进程占有多少内存
8./proc目录下什么

cpp问题

1.为什么要内存对齐
2.内存对齐的规则是怎么样的
3.析构函数要设置为虚函数吗为什么
4.函数和模版的区别
5.他们在什么时候确定的,都是在编译期决定的
6.数据库大表是怎么分表的

面筋17

1、项目中,常见的顺序读随机读写的性能大概多少

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
————————————————————————————————————————————
所以对于ssd来说
1、顺序的读写使用的每秒的吞吐量来完成的,目前市场上常见的ssd的顺序读写的吞吐量维持在500M/s左右,其中来说顺序读的吞吐量普遍高于顺序写的吞吐量,顺序写维持在400M/s左右

2、对于4KB的随机读写来看,主要关注的是随机的io次数,所以衡量的指标一般都是IOPS,那么市场上常见的ssd的随机读的IOPS性能在10~45k IOPS左右,而由于随机写可能会有缓存的优化影响,随机写一般要好于随机读,IOPS性能在55k~50iops左右,三星可能更好。

3、对于吞吐量这个指标来说,磁盘的吞吐量一般是100MB左右,而普通sata接口的ssd吞吐量在500MB左右,而对于PCIE ssd的吞吐量可能上啊G/s,多通道目前最快的甚至顺序写的吞吐量甚至达到了10G/s

4、最能考验ssd性能的是随机的读写,写可能还有优化,所以最能考验的是随机读性能。
————————————————————————————————————————————

2、项目的整体框架是怎么样的,

如果更改为其他的存储介质怎么用
为什么不用现有的仿真器

3、进程和线程的区别
4、项目中是怎么用到进程和线程的
5、还了解一些其它的分布式缓存的知识吗
6、redis,memcache

猜你喜欢

转载自blog.csdn.net/u012414189/article/details/84583237