这里写自定义目录标题
简介
libco是微信后台大规模使用的c/c++协程库,2013年至今稳定运行在微信后台的数万台机器上。
libco通过仅有的几个函数接口 co_create/co_resume/co_yield 再配合 co_poll,可以支持同步或者异步的写法,如线程库一样轻松。同时库里面提供了socket族函数的hook,使得后台逻辑服务几乎不用修改逻辑代码就可以完成异步化改造。
libco的特性
1、无需侵入业务逻辑,把多进程、多线程服务改造成协程服务,并发能力得到百倍提升;
2、支持CGI框架,轻松构建web服务(New);
CGI:
通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。
组成CGI通信系统的是两部分:一部分是html页面,就是在用户端浏览器上显示的页面。另一部分则是运行在服务器上的Cgi程序。它们之间的通讯方式如下图:
3、支持gethostbyname、mysqlclient、ssl等常用第三库(New);
(1) gethostname
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构的指针。结构的声明与 gethostbyaddr()中一致。
返回对应于给定主机名的主机信息。
#include <winsock2.h>
structhostent *gethostbyname(constchar*name);
name:指向主机名的指针。
返回类型
structhostent
{
char*h_name;
char** h_aliases;
shorth_addrtype;
shorth_length;
char** h_addr_list;
};
Linux版
#include <netdb.h>
structhostent *gethostbyname(constchar*hostname);
返回:非空指针——成功,空指针——出错,同时设置h_errno
(2) mysqlclient
要想使 python 可以操作 mysql 就需要 MySQLdb 驱动,它是 python 操作 mysql 必不可少的模块。
使用pip安装
pipinstallmysqlclient
(3) ssl
Secure Socket Layer,为Netscape所研发,用以保障在Internet上数据传输的安全,利用数据加密(Encryption)技术,可确保数据在网络上的传输过程中不会被截取及窃听。
1)认证用户和服务器,确保数据发送到正确的客户机和服务器;
2)加密数据以防止数据中途被窃取;
3)维护数据的完整性,确保数据在传输过程中不被改变。
4、可选的共享栈模式,单机轻松接入千万连接(New);
5、完善简洁的协程编程接口
6、类pthread接口设计,通过co_create、co_resume等简单清晰接口即可完成协程的创建与恢复;
7、__thread的协程私有变量、协程间通信的协程信号量co_signal (New);
8、语言级别的lambda实现,结合协程原地编写并执行后台异步任务 (New);
9、基于epoll/kqueue实现的小而轻的网络框架,基于时间轮盘实现的高性能定时器
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。
注释
Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!
Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!
阻塞IO:当你去读一个阻塞的文件描述符时,如果在该文件描述符上没有数据可读,那么它会一直阻塞(通俗一点就是一直卡在调用函数那里),直到有数据可读。当你去写一个阻塞的文件描述符时,如果在该文件描述符上没有空间(通常是缓冲区)可写,那么它会一直阻塞,直到有空间可写。以上的读和写我们统一指在某个文件描述符进行的操作,不单单指真正的读数据,写数据,还包括接收连接accept(),发起连接connect()等操作…
非阻塞IO:当你去读写一个非阻塞的文件描述符时,不管可不可以读写,它都会立即返回,返回成功说明读写操作完成了,返回失败会设置相应errno状态码,根据这个errno可以进一步执行其他处理。它不会像阻塞IO那样,卡在那里不动!!!
(1)select==>时间复杂度O(n)
它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。
(2)poll==>时间复杂度O(n)
poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,但是它没有最大连接数的限制,原因是它是基于链表来存储的.
(3)epoll==>时间复杂度O(1)
epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
(4)kqueue
kqueue与epoll非常相似,最初是2000年Jonathan Lemon在FreeBSD系统上开发的一个高性能的事件通知接口。注册一批socket描述符到 kqueue 以后,当其中的描述符状态发生变化时,kqueue 将一次性通知应用程序哪些描述符可读、可写或出错了。