面试题小记

  1. 讲一下BIO,NIO,AIO的区别

    1. 回答:IO分为两个阶段:数据准备阶段和数据拷贝阶段;BIO需要等待数据准备和数据拷贝;NIO会轮询数据是否准备完成,需要等待数据拷贝;AIO会在数据准备完成和数据拷贝完成后收到通知,然后执行异步处理逻辑

  2. 一个压测软件叫做Webbench,可以直接在社长的Gtihub里面下载,解压,然后在解压目录打开终端运行命令(-c表示客户端数, -t表示时间):

    1
    
    ./webbench -c 10001 -t 5 http://127.0.0.1:9006/
    
  3. Webbench是什么,介绍一下原理
    父进程fork若干个子进程,每个子进程在用户要求时间或默认的时间内对目标web循环发出实际访问请求,父子进程通过管道进行通信,子进程通过管道写端向父进程传递在若干次请求访问完毕后记录到的总信息,父进程通过管道读端读取子进程发来的相关信息,子进程在时间到后结束,父进程在所有子进程退出后统计并给用户显示最后的测试结果,然后退出。
  4. Redis中map怎么扩容,扩容时会影响缓存吗                                                                            底层有两个dict,一个dict负责请求,到达负载比例进行扩容,渐进式扩容,一部分一部分转移到新的dict   

    渐进式 rehash 步骤如下: 1.  给「哈希表 2」 分配空间; 2. 在 rehash 进行期间,每次哈希表元素进行新增、删除、查找或者更新操作时,Redis 除了会执行对应的操作之外,还会顺序将「哈希表 1 」中索引位置上的所有 key-value 迁移到「哈希表 2」 上;3 . 随着处理客户端发起的哈希表操作请求数量越多,最终在某个时间点会把「哈希表 1 」的所有 key-value 迁移到「哈希表 2」,从而完成 rehash 操作。   这样就巧妙地把一次性大量数据迁移工作的开销,分摊到了多次处理请求的过程中,避免了一次性 rehash 的耗时操作。 在渐进式 rehash 进行期间,新增一个 key-value 时,会被保存到「哈希表 2 」里面,而「哈希表 1」 则不再进行任何添加操作,这样保证了「哈希表 1 」的 key-value 数量只会减少,随着 rehash 操作的完成,最终「哈希表 1 」就会变成空表。

  5. 跳表结构了解吗                                                                                                                          第一层是双向链表,会有多层来作为链表的索引。二叉查找树的时间复杂度是O(logn),空间复杂度是O(n);跳表的时间复杂度是O(log_{k}n),k为跳表索引步长,空间复杂度是O(n)

  6. binlog和redolog做数据恢复的区别

    回答:redolog有大小限制,数据可能被覆盖,用来处理紧急数据库故障;binlog是全量操作日志,可以进行做全量的数据恢复

    补充:

    binlog和redolog都是用于MySQL数据库的日志。它们都可以用于数据恢复,但是它们的使用场景和恢复方法有所不同。

    binlog是MySQL的二进制日志,它记录了所有对MySQL数据库的修改操作,包括插入、更新和删除等。binlog可以用于恢复MySQL数据库到指定的时间点或者指定的事务。具体来说,可以使用mysqlbinlog命令将binlog文件解析成SQL语句,然后再执行这些SQL语句,从而恢复MySQL数据库的状态。

    redolog是MySQL的重做日志,它记录了所有对MySQL数据库的修改操作,但是只记录了物理操作,比如页的修改。redolog可以用于恢复MySQL数据库的崩溃恢复,即在MySQL崩溃后,通过重做日志,将数据库恢复到最近一次提交的状态。具体来说,可以使用innodb_recovery命令来进行崩溃恢复,该命令会根据重做日志来恢复数据库。

    因此,binlog和redolog都可以用于数据恢复,但是它们的使用场景和恢复方法有所不同。binlog主要用于数据恢复到指定时间点或者指定事务,而redolog主要用于MySQL的崩溃恢复。

  7. 一致性哈希算法就很好地解决了分布式系统在扩容或者缩容时,发生过多的数据迁移的问题。

    一致哈希算法也用了取模运算,但与哈希算法不同的是,哈希算法是对节点的数量进行取模运算,而一致哈希算法是对 2^32 进行取模运算,是一个固定的值一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上一致性哈希算法虽然减少了数据迁移量,但是存在节点分布不均匀的问题. ===> 应对方法:不再将真实节点映射到哈希环上,而是将虚拟节点映射到哈希环上,并将虚拟节点映射到实际节点,所以这里有「两层」映射关系。

8 . 右值引用有什么作用

  • 右值引用是C++11引入的特性,它是指对右值进行引用的一种方式。右值引用的作用主要有两个:

  • 可以通过右值引用来实现移动语义。移动语义可以在不进行深拷贝的情况下,将对象的资源所有权从一个对象转移到另一个对象,从而提高代码的效率。

  • 右值引用还可以用于完美转发。在函数模板中,通过使用右值引用类型的形参来接收参数,可以实现完美转发,即保持原参数的值类别(左值还是右值),将参数传递给另一个函数

六、static的作用(作用域限制)

static
  • 不考虑类的情况

    • 有时候希望某些全局变量或者函数只在本文件中被使用,而不能被其他外部文件引用,这个时候可以在全局变量前加一个static说明,这样不同的人编写不同的变量或者函数时不用担心重名的问题,即使重名了也互不干扰

    • 默认初始化为0,包括未初始化的全局静态变量与局部静态变量,都存在全局未初始化区

    • 静态变量在函数内定义,始终存在,且只进行一次初始化,具有记忆性,其作用范围与局部变量相同,函数退出后仍然存在,但不能使用

  • 考虑类的情况

    • static成员变量:只与类关联,不与类的对象关联。定义时要分配空间,不能在类声明中初始化,必须在类定义体外部初始化,初始化时不需要标示为static;可以被非static成员函数任意访问。

    • static成员函数:不具有this指针无法访问类对象的非static成员变量非static成员函数;不能被声明为const、虚函数和volatile;可以被非static成员函数任意访问

静态局部变量:
  1. 静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在整个程序运行期间始终存在。

  2. 静态局部变量只初始化一次,并且之后再次调用函数时不再重新分配空间和赋初值,而保留上次函数调用结束时的值(而普通局部变量每调用一次就会重新分配空间并赋一次初值)

  3. 静态局部变量默认初始化为0

  4. 函数调用结束之后静态局部变量依然存在,但是只能在该函数内进行使用该静态局部变量,

extern的作用(作用域扩展)
  1. 将全局变量的作用域扩展到其定义之前:如果全局变量不在文件的开头定义,其作用范围只限定于从定义处到文件结尾,如果在定义点之前的函数想引用该变量,就应该在引用之前使用extern关键字对该变量进行声明,之后该全局变量的作用域就从声明处一直到文件结尾了

  2. 将某一个源文件中全局变量的作用域扩展到其他源文件中:一个C++项目很多情况是由多个源文件构成,如果在一个文件中想引用另一个文件中已定义的全局变量,比如现在两个文件都要使用到同一个全局变量int a,正确的做法应该是:在一个文件中定义变量a,而在另一个文件中使用extern int a;对该变量进行声明,这样就可以两个文件同时使用同一个变量了

const
  • 不考虑类的情况

    • const常量在定义时必须初始化,之后无法更改

    • const形参可以接收const和非const类型的实参,例如// i 可以是 int 型或者 const int 型void fun(const int& i){ //...}

  • 考虑类的情况

    • const成员变量:不能在类定义外部初始化,只能通过构造函数初始化列表进行初始化,并且必须有构造函数;不同类对其const数据成员的值可以不同,所以不能在类中声明时初始化。

    • const成员函数:const对象不可以调用非const成员函数;非const对象都可以调用;不可以改变非mutable(用该关键字声明的变量可以在const成员函数中被修改)数据的值。

七、C++ sort()函数实现

sort()源码中采用的是一种叫做IntroSort内省式排序的混合式排序算法,

1.首先进行判断排序的元素个数是否大于stl_threshold,stl_threshold是一个常量值是16,意思就是说我传入的元素规模小于我们的16的时候直接采用插入排序。(为什么用插入排序?因为插入排序在面对“几近排序”的序列时,表现更好,而快排是通过递归实现的,会为了极小的子序列产生很多的递归调用在区间长度小的时候经常不如插入排序效率高)

2.如果说我们的元素规模大于16,那就需要去判断如果是不是能采用快速排序,怎么判断呢?快排是使用递归来实现的,如果说我们进行判断我们的递归深度有没有到达递归深度的限制阈值2*lg(n),如果递归深度没达到阈值就使用快速排序来进行排序

3.如果说大于我们的最深递归深度阈值的话,这个时候说明快排复杂度退化了(比如很不巧基准元素多次选取到了当前区间中最小或最大的元素。这种情况下,每次划分只能将区间缩小1个元素,造成递归深度过深),就会采用我们的堆排序,堆排序是可以保证稳定O(nlogn)的时间复杂度的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值