python高性能之路:使用C/C++编写扩展

脚本语言一般使用c等静态语言编写扩展提高性能,下面使用cpp编写一个实现两数之和的python扩展函数

完成案例代码参考:https://1drv.ms/u/s!AquRvPzqx59RjAZ3wk6qpzqEDgF9?e=jZe5hu

构建python环境

减少扩展开发对系统python的影响,建议使用venv创建一个新的python开发环境

virtualenv ~/develop/venvpy3

操作效果如下

使用命令source ~/develop/venvpy3/bin/activate激活即可

创建扩展文件sumext.cpp

sumext.cpp

#include <iostream>
#include <stdio.h>
#include <Python.h>

using namespace std;

主要是引入依赖的Python.h文件头即可,其它头文件按需引入使用

Read more   2020/4/27 posted in  python 源码分析

twitter公司redis&memcached中间件twemproxy源码分析(一)

twemproxy是redis和memcached连接池中间件

github项目地址:https://github.com/twitter/twemproxy

项目简介参考:https://github.com/twitter/twemproxy#features

文档参考:https://github.com/twitter/twemproxy/blob/master/notes/recommendation.md

核心流程

主流程就是启动了一个事件循环,所有的逻辑通过事件出发调用回调函数执行

Read more   2019/10/17 posted in  源码分析

nginx网络通信模块设计与实现分析

nginx作为后端程序不可缺少的中间件,凭借其优异的性能和稳定性,获得了大量的用户

目录结构


nginx的文件目录非常清晰,虽然有6个目录,但是可以归成两类,core目录存放nginx生命周期相关的函数,比如master、worker进程的创建,模块构造函数调用,核心数据结构和算法实现

其它目录主要就是存放nginx功能的扩展了、nginx几乎所有的功能都是通过扩展实现的

入口程序

src/core/nginx.c::main()

在入口程序中,nginx主要是处理了命令行参数,如果没有带参数运行nginx,则启动nginx服务器ngx_master_process_cycle(cycle

核心调用如下

  1. ngx_strerror_init() 初始化错误码存放链表
  2. ngx_get_options(argc, argv) 将命令行参数解析到全局变量
  3. 初始化日志系统: ngx_log_init(ngx_prefix)
  4. ngx_save_argv(&init_cycle, argc, argv) 保存所有命令行参数到全局变量
  5. ngx_process_options(&init_cycle)

给启用的nginx模块进行编号

ngx_max_module = 0;
for (i = 0; ngx_modules[i]; i++) {
    ngx_modules[i]->index = ngx_max_module++;
}
Read more   2019/9/15 posted in  源码分析

memcached中的经典数据结构hash链表和LRU删除策略的应用

hash链表是memcached核心的数据结构了,hash表用于快速读取、写入缓存数据(item结构),链表用于实现lru策略,lru用于内存不足时的兜底策略,有效防止了内存不足时造成宕机

缓存操作

memcached中使用struct _stritem结构体代表缓存,这个结构体被typedef定义成了item类型,对这个item结构体的操作都在item.c中,函数列表如下

函数 作用
item_init 初始化lru链表头尾指针、item数量数组
item_make_header 计算一个item占用的内存字节数
item_alloc 从slab中分配出item的内存
item_free 把item内存还给slab
item_size_ok 检查item内存大小是否超过了slab允许的范围
item_link_q 把item加入到lru链表头
item_unlink_q 从链表中删除item
item_link 把item插入hash表,同时加入lru链表中(item_link_q)
item_unlink 把item从hash表中删除,同时从lru链表中删除(item_unlink_q)
item_remove 把item内存还给slab,带异常检查
item_update 修改item,同时按照lru规则重建这个item在lru链表中的位置
item_replace 替换item,和item_update的区别时,这个不会修改item的最后访问时间
item_cachedump 获取指定slab的所有item的key和value的大小
item_stats 获取所有lru链表的大小
item_stats_sizes 统计item的大小

可以看到这个item的操作就用到了hash表和链表,item是在hash表和链表上进行的,即对缓存item的操作,会同时影响到hash表和链表两种数据结构的构建

hash表构建

Read more   2019/9/8 posted in  源码分析

基础数据结构-用链表实现队列和栈

链表在memcached、redis中作为核心数据结构出现。相比数组,链表能动态增减容量,就比数组要灵活,并且hash表结构一般都使用链表进行数据存储

完整案例代码已上传github: https://github.com/neatlife-learn/mydatastructure

队列

元素结构

对应代码如下

typedef struct _element {
    struct _element *previous;
    struct _element *next;
    void *value;
} element;

队列结构

一个队列中包含多个元素,为了能够方便的得到这个队列头和尾,以及队列里的元素个数,使用这个queue结构来存放这些信息

Read more   2019/8/28 posted in  源码分析

memcached内存分配策略源码分析

本文基于memcached 1.2.0写成

memcached的内存分配器slab.c不过300行代码,还是比较容易上手分析的。

内存模型如下:

一个slabclass_t管理了多个slab,每个slab被称为内存页,每个slab管理多个item的内存空间

核心函数

函数名 作用
slabs_init 初始化slabclass_t结构体数组
slabs_clsid 通过内存大小从slabclass_t数组中找到最小能满足的结构体
slabs_preallocate 给每个slabclass_t先分配一个slab(页)的内存(1mb)
slabs_newslab 给指定的slabclass分配一个新的slab存放到slab_list上,同时slabs、end_page_ptr、end_page_free发生相应变化
grow_slab_list 动态增加slab_list数组的大小
slabs_alloc 从内存分配器中取出一个空的item内存来使用
slabs_free 将item所在的内存指针重新标记成可使用,相当于删除了item
slabs_stats 从slabclass_t结构体上获取内存分配器的使用情况
Read more   2019/8/23 posted in  源码分析

三分钟上手linux系统开发

linux系统编程,主要使用c语言,c++是c的超集,也是可以的

完整项目代码已上传github:https://github.com/neatlife/my-tlpi-book

获取可用环境

可以使用虚拟机安装一个linux系统进行linux系统开发,虽然mac os和linux非常相似,但是和linux还是有很多小区别的,装虚拟机是最省事的
这里使用elementary os,下载地址参考:https://elementary.io/zh_CN/

安装时,选linux 4.x以上的内核版本即可

redis网络通信模块设计与实现分析

redis的通信模块封装得非常简单易用,可以直接用到自己项目中,学习下也是很有价值的。

本文基于redis源码4.0.1写成,redis源码下载:https://github.com/antirez/redis/archive/4.0.1.tar.gz

文件结构

redis的网络通信模块由8个文件构成

作用如下

文件 作用
ae.c 统一epoll、evport、kqueue、select网络事件处理接口, 函数实现
ae.h 统一epoll、evport、kqueue、select网络事件处理接口,函数原型,共享结构体定义
ae_epoll.c 封装epoll网络事件处理库到统一的接口
ae_evport.c 封装evport网络事件处理库到统一的接口
ae_kqueue.c 封装kqueue网络事件处理库到统一的接口
ae_select.c 封装select网络事件处理库到统一的接口

统一网络库底层接口

被统一的网络事件处理接口如下,参考:ae_epoll.c, ae_evport.c, ae_kqueue.c, ae_select.c

Read more   2019/8/9 posted in  源码分析 Redis

xaop源码分析

项目地址:https://github.com/liqiongfan/xaop

思路: hook掉php执行函数的方法(zend_execute_ex),然后使用call_user_function调用自定义的回调函数

文件和作用

Xaop操作类的所有方法:kernel/xaop.c

Xaop操作类会使用的宏,比如解析和检查方法的参数:kernel/xaop.h

扩展调用php函数的函数:kernel/helper.c 和 kernel/helper.h

替换php的zend_execution_ex: kernel/exec.c 和 kernel/exec.c

解析用户编写的annotation的相关逻辑:kernel/parsing.c 和 kernel/parsing.h

全局变量定义在: php_xaop.h

全局工具类zend_class_entry的声明*annotation_ce, *doc_ce, *xaop_ce:kernel/classes.c

检查参数是否合法

#define CHECK_PARAM() do {\
    if ( Z_TYPE_P(class_name) != IS_STRING && Z_TYPE_P(class_name) != IS_NULL ) { \
        php_error_docref(NULL, E_ERROR, "First argument need to be a valid class name or NULL");\
        return ;\
    }\
    if ( ZSTR_LEN(function_name) && '*' == ZSTR_VAL(function_name)[0] ) { \
        php_error_docref(NULL, E_ERROR, "Function name mustn't be `*`.");\
        return ;\
    }\
    if ( !zend_is_callable(aop, IS_CALLABLE_CHECK_NO_ACCESS, NULL) ) {\
        php_error_docref(NULL, E_ERROR, "Third argument is expected to be a valid callback");\
        return ;\
    }\
} while(0)
Read more   2019/6/20 posted in  源码分析 PHP

小微http服务器Tinyhttpd源码分析

完整源代码参考:https://github.com/EZLippi/Tinyhttpd/blob/master/httpd.c

这个项目的调用关系图如下

库文件

#include <stdio.h> 提供perror函数
#include <sys/socket.h> 提供 accept等socket函数
#include <sys/types.h> 提供 u_short 类型
#include <netinet/in.h> 提供sockaddr_in结构体
#include <arpa/inet.h> 提供htons函数
#include <unistd.h> 提供close, dup, dup2等函数
#include <ctype.h> 提供isspace函数
#include <strings.h> 提供strcasecmp函数
#include <string.h> 提供strcat函数
#include <sys/stat.h> 提供检查文件是否存在的stat函数
#include <pthread.h> 提供pthread_create函数
#include <sys/wait.h> 提供wait函数
#include <stdlib.h> 提供printf函数
#include <stdint.h> 提供intptr_t类型
Read more   2019/6/17 posted in  源码分析

使用gdb调试工具上手调试php和swoole源码

swoole作为php的核心项目,php和swoole都具有一定的研究价值,由于是c语言编写的项目,要上手进行调试,那么最好用的调试工具就是gdb了

这个gdb调试工具功能强大,支持的选项也是非常多,下面就总结出来常用的命令

编译源码添加调试信息

在编译时把调试信息编译进生成的二进制文件中,需要给gcc编译器加上-g参数,比如编译php的Makefile中是这样的

加上-g参数就已经有调试信息了,-O0是关闭gcc的优化,这个gcc优化后会在调试时丢失一部分调试信息,所以一般建议关闭

这样在gdb里面就可以随时查看当前执行到源码的那个地方了,能够显著提升调试的效率

查看源码

Read more   2019/5/18 posted in  GDB PHP SWOOLE 源码分析

在phpstorm中三分钟搭建laravel框架源码阅读环境

laravel框架作为php语言排名第一的框架,源码也是非常值得研究的

作者在phpstorm里搭建了一套源码阅读环境,研究搭建这套环境花了些时间,作者对这个搭建步骤进行优化总结,使用下面的步骤就可以快速完成搭建了

下载源代码

github源码地址:https://github.com/laravel/framework

使用git下载源码

git clone https://github.com/laravel/framework.git

效果如下

下载依赖

laravel框架使用composer管理依赖,进入到framework目录,使用composer install命令下载依赖就可以了,命令如下

cd framework
composer install

查看执行效果:

Read more   2018/5/13 posted in  LARAVEL 源码分析