Linux C/C++服务器
异步请求与协程
1.1 什么是异步?
什么是异步?什么是同步?
同步:为一发一收,发完之后阻塞等待回传数据,处理完成然后再发下一条
异步:一直发,commit提交请求接口会一直连续提交请求,有一个专门的等待回传数据的线程,这里我们用epoll来管理接收数据的fd
1.2 DNS请求示例
以DNS为例,演示下同步和异步性能对比,分别向dns服务器发送45个网址,解析返回对应的ip信息,查看用时
- 同步用时1194ms
- 异步用时54ms
异步请求池应用:我们自己的服务器与mysql服务器、redis服务器、grpc等进行数据收发时会显著提升服务器性能
1.3 多线程实现异步请求池
发送和接收要在不同的线程中进行,接收数据要用epoll来管理,通过fd来确认接收的数据是哪个请求的回传数据
- 创建数据接收线程
- 创建管理fd的epoll
1.3.1 主要的接口组成
- commit();
- thread_callback(); epoll_wait();
- init_ctx(); epoll_create(); pthread_create();
- destory_ctx(); pthread_cancel(threadid);close(fd);
代码就是示例中的async_dns_client_noblock.c,可以把dns协议换成http,就是异步的http请求
1.3.2 实现思路
- dns_async_client_init()接口:epoll_create(1)创建epfd,pthread_create()创建接收回传数据线程
- dns_async_client_proc()接口:epoll_wait()等待回传数据事件,就绪后会recv,接受完close(fd)
- dns_async_client_commit()接口:socket()创建sockfd,把dns协议转为requset数据发送包,connect()连接dns服务器,sendto()发送请求,epoll_ctl(ctx->epfd, EPOLL_CTL_ADD, sockfd, &ev)将创建的sockfd添加到epoll中
- main函数中for循环发送45个请求,getchar()防止程序结束
2.1 协程实现异步(单线程)
协程:同步的编程方式,异步的性能;怎么理解? 其实协程干了上边接收线程干的活,也有人称协程为轻量级的线程,那它是怎么干这个活的呢?主旨思想其实就是jump跳转
在千万级io或者更高的量级上使用的较多
协程异步(替换接收线程)思路:
- 检测sockfd是否就绪
- if就绪,执行recv_from()
- if没有就绪,跳转,跳转至commit代码段,发送新的请求
//伪代码
int async_recv_from(int sockfd){
epoll_create();
while(1){
int nready=epoll_wait(epfd, events, EVENTS_LENGTH, 0); //非阻塞
if(events[i].events & EPOLLIN){
recv_form();
}else{
epoll_ctl(epdf, sockfd...);
//跳转至commit()
longjmp();
}
}
}
int commit(){
for(){
send();
}
}
协程实际使用是比较复杂的,需要实现协程调度器,类似于线程调度器,感兴趣可以去找下开源的代码