C++的预处理机制令人诟病的一点是在不同的编译器中的表现是不同的,在boost/preprocessor/config/config.hpp列举出了非常多的case,所以在本篇文章中我们只考虑g++-7的编译结果。此外,出于便于阅读的考虑,对名字进行了简化,去掉了诸如BOOST_PP
等前缀。
Python中join不能响应信号的问题
在文章subprocess模块用法中介绍了Python中的threading.Thread.join()
时不能响应信号的问题。这个问题被Python官方标记为Bug。
Python官方的Issue指出这个Bug与Python的signal、基础线程库thread(C实现)和高级线程库threading(Python封装)都有关,下面首先概览这三个模块的实现,接着通过编译调试的方式来观赏这个Bug的具体过程。
Redis底层对象实现原理分析
我将直接根据github上的unstable分支代码分析。主要是2018年7月版本(dict实现的大部分)的和2020年8月版本(其他部分)的,所以可能会有细微差别。因为Redis的代码比较好读,并且质量很高。这里还推荐《Redis设计与实现》一书,它介绍了Redis中部分比较有趣的设计思路,可惜还有些没有覆盖到,本文中对这些有趣的设计也进行了论述。
Redis中主要包含了字符串STRING、列表LIST(双向链表)、集合SET、哈希表HASH、有序集合ZSET五种最常见的类型。在后续的版本中,还提供了bitmap、geohash、hyperloglog、stream这四种类型。
这些对象依赖于一些内部结构,包括字符串(SDS)、哈希表(dict)、链表(list)、跳表(zskiplist)、压缩双向表(ziplist)、快表等。注意出于性能原因,一个对象的实现往往根据具体的内容而选择不同的实现。列举如下:
- STRING
使用int、sds(raw)或者embstr。
下面的类型也是使用STRING的存储的:- hyperloglog
- bitmap
- HASH
使用dict或者ziplist方案。 - LIST
3.0是使用list或者ziplist的方案。
目前使用快表。 - SET
使用dict或者intset的方案。 - ZSET
视数据规模选用ziplist和skiplist+dict的方案。
下面的类型也是使用ZSET的存储的:- GEOHASH
本文中不介绍的是,它们在系列的其他文章中讲解:
- Redis基础设施
- Redis Sentinel
- Redis Cluster
- Redis AOF/RDB
最后,本文的主体部分已经完成,但后续仍然会进行修订,或者补充。
subprocess模块用法
在Python中我们可以通过os.system
来以控制台的形式运行程序,但当涉及到需要进行进程间通信时,就需要用到subprocess模块。本文原来是和multiprocessing作为一个整体来介绍的,后来进行了拆分,但内容仍然会有所重叠,并且会涉及Python的线程和进程相关机制。
Python2字符编码
字符编码
我们通常见到的字符串编码主要是三种GB2312/GBK、Unicode、UTF-8。GB2312/GBK是多字节(multibytes)编码的一种,属于“ASCII的加强版”,与之平行的由Big5、ShiftJIS之类的编码各自为政,所有这些用两个字节表示汉字的多字节编码标准统称为ANSI编码,同样的汉字在不同的ASNI编码中的表示是不同的。为了避免这个问题,Unicode应运而生,将全世界所有的字符统一编码到一个定长的结构中。Unicode解决了统一编码的问题,但带来了新的问题。第一点,Unicode和ASCII不兼容了,这是因为ASCII只有一个字节,而这一个字节肯定装不下Unicode。第二点,用Unicode传输开销变大了,这是因为很多文档二十六个字母(1个字节)就能解决了,用Unicode多了很多冗余的字节。因此UTF-8应运而生。UTF-8对Unicode进行变长编码(我们可以想象下Huffman树),通常长度在1-4字节。目前Linux系统使用的是UTF-8编码,而Windows内部则是UTF-16LE/GBK编码。
Google Kickstart 2018 Round B题解
继续写第二轮
Google Kickstart 2018 Round A题解
Kickstart,我又回来了,今年是校招年了,所以加油吧。
常用语言的时间模块
在相当长的时间里面,与时间相关的库我总是很不熟练,每次用到总要卡一下,慢慢Google,这次索性直接记下来,这样下次遇到我就可以查自己的博客而不是Google了(反正我是不会记在脑子里面的是吧~)。
gRPC配置与用法
本文中介绍了如何配置gRPC和brpc。
C++智能指针的使用与实现
在C++史前时代只有一种智能指针std::auto_ptr<T>
,它的作用方式类似一个lock_guard<T>
,或者经过封装的RAII。但在使用中发现,依托于RAII是不够的,为了方便地实现更复杂逻辑下的资源管理,我们需要从资源的所有权上对智能指针进行更加细致的分类。在C++11之后,标准库引入了std::shared_ptr<T>
、std::unique_ptr<T>
、std::weak_ptr<T>
来替换之前的std::auto_ptr<T>
。
截至目前为止,我基本没怎么用过智能指针,一方面之前做的项目都比较局限,使用RAII或者对象池会更方便,另一方面智能指针和对C风格的兼容性也不是很好,例如很多C风格的代码要求bit-wise而不是member-wise的操作,而智能指针并不是trivial的,而且具有传染性,所以往往适用不了。
【未完待续】