今天面试惨败,面试官问了不到10个问题就让我出来写题了……对其中的一个题目印象深入:c++
Redis获取字符串长度的复杂度是多少?
刚开始我是一脸懵逼的,由于不清楚Redis
的字符串类型是怎么实现的,因此彻底无法答下去了……回来后立刻开始学习。面试
字符串是Redis
里很是常见的类型,而用C
实现的Redis
和Java
不同。在C
里字符串是用长度为N+1
的字符数组实现的,且使用空字符串'\0'
做为结束符号。获取字符串的长度须要遍历一遍,找到空字符串'\0'
才知道字符串的长度,复杂度是O(N)
。数据库
若是有一个长度很是大的字符串,单线程的Redis
获取它的长度就可能会阻塞好久,这是不能接受的,因此Redis
须要一种更高效的字符串类型。数组
Redis
实现了一个叫SDS(simple dynamic string)
的字符串类型,其中有两个变量来分别表明字符串的长度和字符数组未使用的字符数量,这样就能够用O(1)
的复杂度来获取字符串的长度了,并且一样也是使用空字符串'\0'
做为结束符号。学习
struct sdshdr { // 字符串长度 int len; // 字符数组未使用的字符数量 int free; // 保存字符串的字符数组 char buf[]; }
如今已经能够回答上面的面试题了,实际上是很是简单的一个问题,怪不得答不出来面试官立刻就说面试结束了……优化
SDS
在字符数组空间不足于容纳新字符串的时候会自动扩容。ui
若是把一个C
字符串拼接到一个SDS
后面,当字符数组空间不足时,SDS
会先扩容到恰好能够容纳新字符串的长度,而后再扩充新字符串的空字符长度,最终SDS
的字符数组长度等于 2 * 新字符串 + 1(结束符号'\0')
。不过当新字符串的大小超过1MB
后,扩充的空字符长度大小会固定为1MB
。spa
之因此会有这个机制,是由于Redis
做为一个NoSQL
数据库,会频繁的修改字符串,扩容机制至关于给SDS
作了一个缓冲池。把SDS
连续增加N
次字符串须要内存重分配N
次优化成了SDS
连续增加N
次字符串最多须要内存重分配N
次,这其实和Java
里的StringBuilder
实现思想是同样的。线程
此次翻车是有缘由的,我看过两本关于Redis
的书,里面都是讲Redis
如何实战的可是并无讲Redis
的设计和实现。这也就致使了面试很尴尬,由于面试官最喜欢问原理相关的东西了,因此之后学习技术的时候不要从实战类的书籍开始了,仍是先看懂原理比较好。设计
这是《Redis设计与实现》
里字符串一节的总结。