共计 4616 个字符,预计需要花费 12 分钟才能阅读完成。
本文转载自自己头条号:https://www.toutiao.com/i6926789516594479624/
转载请注明出处,感激!
对于宽广 C 语言开发者来说,不足相似 C ++ STL 和 Boost 的库会让开发受制于根底库的匮乏,也因而导致了开发效率的骤降。这也使得例如 libevent 这类事件库(根底组件库)一时间大红大紫。
明天,码哥给大家带来一款根底库,这套库不仅仅提供了罕用的数据结构、算法,如红黑树、斐波那契堆、队列、KMP 算法、RSA 算法、各类哈希算法、数据恢复算法等等,还提供了多过程框架、多线程框架、跨平台高性能事件等实用内容。留神:这是一款不依赖第三方的库。
除此以外,它也是笔者之前文章(Melang 脚本语言)中的外围库。这也就意味着,应用该库,不仅能够疾速取得上述内容,还能够让开发者所构建的零碎很不便地引入脚本语言的性能。
它就是——Melon
Github:https://github.com/Water-Melon/Melon。
上面,码哥便带诸位一览这个库的性能。
数据结构
Melon 中蕴含如下数据结构的实现:
- 双向链表
- 斐波那契堆
- 哈希表
- 队列
- 红黑树
- 栈
其中:
- 双向链表应用宏实现,能够通过两行宏函数即可实现双向队列插入和删除操作的申明和定义。
- 斐波那契堆是一个最小堆,在库中的事件性能中用于实现定时器的保护治理,当然,也能够独自应用。
以上构造简直均可在其对应名称的头文件中找到数据结构定义以及函数定义。
个别状况下,数据结构的应用都是函数调用模式,因而也尽可能升高了不同组件间的耦合度。
算法
Melon 中蕴含的算法如下:
- 加密算法:AES、DES、3DES、RC4、RSA
- 哈希算法:MD5、SHA1、SHA256
- Base64
- 大数计算
- FEC
- JSON
- 矩阵运算
- 里德所罗门编码
- 正则匹配算法
- KMP
如上算法根本都在其各自头文件中能够找到对应的函数申明以及必要的数据结构定义。
其中,FEC 与里德所罗门编码均属于纠错码,FEC 罕用于 RTP 中做数据修复,而里德所罗门编码既能够用于实时语音中丢包复原,也能够用于冗余阵列(RAID)和其余 UDP 丢包复原的场景。对于里德所罗门编码,感兴趣的读者能够浏览码哥之前的文章:神奇的数据恢复算法。
其余组件
后面的都是惯例操作,这里才是重头戏。
Melon 中还包含如下实用组件:
- 内存池
- 数据链
- TCP 封装
- 事件机制
- 文件缓存
- HTTP 解决
- 脚本语言
- 词法分析器
- websocket
- 多过程框架
- 多线程框架
因 Melon 作者 Nginx 中毒较深,所以 Melon 中局部机制与 Nginx 较为类似。
内存池:这里内存池不仅反对对从堆中调配的内存进行治理,还反对对共享内存的治理。
数据链与 TCP 封装:TCP 封装中蕴含了阻塞与非阻塞下的收发逻辑,并利用数据链构造来寄存发送数据与接收数据。
事件机制:事件机制中不仅反对 epoll、select,还反对 Kqueue,库在编译前会自行检测平台反对状况。事件蕴含了:
- 句柄(文件描述符)事件:读、写、出错事件,以及超时事件(次要用于超时断开链接);
- 定时事件(与句柄超时是两码事);
- 信号处理事件:这里的信号处理并非一个信号只能有一个处理事件,而是设置多少个处理函数就会执行多少个;
文件缓存:参考 Nginx 文件缓存,防止对同一文件的反复关上节约文件描述符资源。
HTTP:蕴含了 HTTP 的接管解析和发送,该套接口依赖于 数据链 构造来进行解决,因而可配合 TCP 封装 一起应用。
脚本语言:内容较多,可另行参考:Melang 脚本语言。
词法分析器:之所以这个独自算一个性能组件,是因为在 Melon 中,配置文件解析就是应用该词法分析器解决的。仅通过三行 C 代码就能够实现一个最最根底的词法分析器,这也归功于 C 语言宏的弱小。
websocket:该局部依赖于 HTTP 组件。
多过程:多过程采纳一主多从模式,主过程做治理,从过程解决理论业务。主过程与从过程之间由 socketpair 相连,因而从过程异样退出,主过程会立即拉起一个新的子过程,同时奴才过程也能够通过该 socketpair 进行数据通信。除了自身子过程能够治理,也能够通过配置文件配置来拉起其余程序作为本人的子过程来治理,有些相似于 supervisord。
多线程:多线程分为两类,一类是惯例的线程池,另一类是模块化的线程。后者也是一主多从模型,主与子之间是通过 socketpair 进行通信,而每一个子线程都有其入口函数(相似 main 函数),每一个子线程通常都是解决一类繁多事务。
应用举例
下面说了那么多,上面就来看一个多过程的例子。
首先,咱们要先装置 Melon:
$ git clone https://github.com/Water-Melon/Melon.git
$ ./configure
$ make
$ sudo make install
$ sudo echo "/usr/local/melon/lib/" >> /etc/ld.so.conf
$ sudo ldconfig
装置好后,Melon 会被装置在 /usr/local/melon 下。
接着,咱们创立一个名为 hello.c 的源文件来实现咱们冀望的性能:
#include <stdio.h>
#include "mln_core.h"
#include "mln_log.h"
#include "mln_event.h"
char text[1024];
static int global_init(void);
static void worker_process(mln_event_t *ev);
static void print_handler(mln_event_t *ev, void *data);
int main(int argc, char *argv[]) {
struct mln_core_attr cattr;
cattr.argc = argc;
cattr.argv = argv;
cattr.global_init = global_init;
cattr.worker_process = worker_process;
return mln_core_init(&cattr);
}
static int global_init(void) {
//global variable init function
int n = snprintf(text, sizeof(text)-1, "hello worldn");
text[n] = 0;
return 0;
}
static void worker_process(mln_event_t *ev) {
//we can set event handler here
//let's set a timer
mln_event_set_timer(ev, 1000, text, print_handler);
}
static void print_handler(mln_event_t *ev, void *data) {mln_log(debug, "%sn", (char *)data);
mln_event_set_timer(ev, 1000, data, print_handler);
}
这段代码次要是初始化了一个全局变量,而后给每一个子过程创立了一个定时事件,即每一秒中输入一个 hello world。
咱们先进行编译链接生成可执行程序:
$ gcc -o hello hello.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon
而后,咱们须要先批改 Melon 库的配置文件:
$ sudo vim /usr/local/melon/conf/melon.conf
log_level "none";
//user "root";
daemon off;
core_file_size "unlimited";
//max_nofile 1024;
worker_proc 1;
thread_mode off;
framework off;
log_path "/usr/local/melon/logs/melon.log";
/*
* Configurations in the 'exec_proc' are the
* processes which are customized by user.
*
* Here is an example to show you how to
* spawn a program.
* keepalive "/tmp/a.out" ["arg1" "arg2" ...]
* The command in this example is 'keepalive' that
* indicate master process to supervise this
* process. If process is killed, master process
* would restart this program.
* If you don't want master to restart it, you can
* default "/tmp/a.out" ["arg1" "arg2" ...]
*
* But you should know that there is another
* arugment after the last argument you write here.
* That is the file descriptor which is used to
* communicate with master process.
*/
exec_proc {// keepalive "/tmp/a";}
thread_exec {
// restart "hello" "hello" "world";
// default "haha";
}
咱们做如下批改:
- framework off; –> framework on;
- worker_proc 1; –> worker_proc 3;
这样,多过程框架将被启用,且会产生三个子过程。
程序启动后如下:
$ ./hello
Start up worker process No.1
Start up worker process No.2
Start up worker process No.3
02/08/2021 09:34:46 GMT DEBUG: hello.c:print_handler:39: PID:25322 hello world
02/08/2021 09:34:46 GMT DEBUG: hello.c:print_handler:39: PID:25323 hello world
02/08/2021 09:34:46 GMT DEBUG: hello.c:print_handler:39: PID:25324 hello world
02/08/2021 09:34:47 GMT DEBUG: hello.c:print_handler:39: PID:25322 hello world
02/08/2021 09:34:47 GMT DEBUG: hello.c:print_handler:39: PID:25323 hello world
02/08/2021 09:34:47 GMT DEBUG: hello.c:print_handler:39: PID:25324 hello world
...
这时,能够 ps 看一下,一共存在四个 hello 过程,一个为主,其余三个为子过程。
小结
事实上,Melon 并不会有过多条条框框须要开发者小心谨慎怕踩坑。与 Skynet 相似,Melon 提供的绝大多数内容都可独立应用,而不用肯定与多过程多线程框架联合。因而,这也给了使用者极大的自由度。
Melon 的官网 QQ 群号:756582294
感激浏览,欢送各位在评论区留言评论。