高性能服务器开发基础系列 (一)主线程与工作线程的分工
admin
2023-03-10 20:41:08
0

服务器端为了能流畅处理多个客户端链接,一般在某个线程A里面accept新的客户端连接并生成新连接的socket fd,然后将这些新连接的socketfd给另外开的数个工作线程B1、B2、B3、B4,这些工作线程处理这些新连接上的网络IO事件(即收发数据),同时,还处理系统中的另外一些事务。这里我们将线程A称为主线程,B1、B2、B3、B4等称为工作线程。工作线程的代码框架一般如下:

while (!m_bQuit)  {
    epoll_or_select_func();

    handle_io_events();

    handle_other_things();
}

epoll_or_select_func()中通过select()或者poll/epoll()去检测socket fd上的io事件,若存在这些事件则下一步handle_io_events()来处理这些事件(收发数据),做完之后可能还要做一些系统其他的任务,即调用handle_other_things()。

这样做有三个好处:

线程A只需要处理新连接的到来即可,不用处理网络IO事件。由于网络IO事件处理一般相对比较慢,如果在线程A里面既处理新连接又处理网络IO,则可能由于线程忙于处理IO事件,而无法及时处理客户端的新连接,这是很不好的。

线程A接收的新连接,可以根据一定的负载均衡原则将新的socket fd分配给工作线程。常用的算法,比如round robin,即轮询机制,即,假设不考虑中途有连接断开的情况,一个新连接来了分配给B1,又来一个分配给B2,再来一个分配给B3,再来一个分配给B4。如此反复,也就是说线程A记录了各个工作线程上的socket fd数量,这样可以最大化地来平衡资源,避免一些工作线程“忙死”,另外一些工作线程“闲死”的现象。

即使工作线程不满载的情况下,也可以让工作线程做其他的事情。比如现在有四个工作线程,但只有三个连接。那么线程B4就可以在handle_other_thing()做一些其他事情。

下面讨论一个很重要的效率问题:

在上述while循环里面,epoll_or_selec_func()中的epoll_wait/poll/select等函数一般设置了一个超时时间。如果设置超时时间为0,那么在没有任何网络IO时间和其他任务处理的情况下,这些工作线程实际上会空转,白白地浪费cpu时间片。如果设置的超时时间大于0,在没有网络IO时间的情况,epoll_wait/poll/select仍然要挂起指定时间才能返回,导致handle_other_thing()不能及时执行,影响其他任务不能及时处理,也就是说其他任务一旦产生,其处理起来具有一定的延时性。这样也不好。

那如何解决该问题呢?

其实我们想达到的效果是,如果没有网络IO时间和其他任务要处理,那么这些工作线程最好直接挂起而不是空转;如果有其他任务要处理,这些工作线程要立刻能处理这些任务而不是在epoll_wait/poll/selec挂起指定时间后才开始处理这些任务。

我们采取如下方法来解决该问题,以linux为例,不管epoll_fd上有没有文件描述符fd,我们都给它绑定一个默认的fd,这个fd被称为唤醒fd。当我们需要处理其他任务的时候,向这个唤醒fd上随便写入1个字节的,这样这个fd立即就变成可读的了,epoll_wait()/poll()/select()函数立即被唤醒,并返回,接下来马上就能执行handle_other_thing(),其他任务得到处理。反之,没有其他任务也没有网络IO事件时,epoll_or_select_func()就挂在那里什么也不做。

这个唤醒fd,在linux平台上可以通过以下几种方法实现:

管道pipe,创建一个管道,将管道绑定到epoll_fd上。需要时,向管道一端写入一个字节,工作线程立即被唤醒。

linux 2.6新增的eventfd:

int eventfd(unsigned int initval, int flags); 

步骤也是一样,将生成的eventfd绑定到epoll_fd上。需要时,向这个 eventfd上写入一个字节,工作线程立即被唤醒。

第三种方法最方便。即linux特有的socketpair,socketpair是一对相互连接的socket,相当于服务器端和客户端的两个端点,每一端都可以读写数据。

int socketpair(int domain, int type, int protocol, int sv[2]);

调用这个函数返回的两个socket句柄就是sv[0],和sv[1],在一个其中任何一个写入字节,在另外一个收取字节。

将收取的字节的socket绑定到epoll_fd上。需要时,向另外一个写入的socket上写入一个字节,工作线程立即被唤醒。

如果是使用socketpair,那么domain参数一定要设置成AFX_UNIX。

由于在windows,select函数只支持检测socket这一种fd,所以windows上一般只能用方法3的原理。而且需要手动创建两个socket,然后一个连接另外一个,将读取的那一段绑定到select的fd上去。这在写跨两个平台代码时,需要注意的地方。

欢迎关注公众号『easyserverdev』。如果有任何技术或者职业方面的问题需要我提供帮助,可通过这个公众号与我取得联系,此公众号不仅分享高性能服务器开发经验和故事,同时也免费为广大技术朋友提供技术答疑和职业解惑,您有任何问题都可以在微信公众号直接留言,我会尽快回复您。
高性能服务器开发基础系列 (一)主线程与工作线程的分工

相关内容

热门资讯

重庆市沙坪坝区中小学科技节在凤... 12月20日,重庆市沙坪坝区中小学科技节在凤鸣山中学举行。本届科技节吸引了来自全区71所中小学、幼儿...
中检天帷取得结合迁移学习的多模... 国家知识产权局信息显示,中检集团天帷网络安全技术(合肥)有限公司取得一项名为“结合迁移学习的多模态数...
【今日要闻】“友乐广西麻将.有... 网上科普关于“友乐广西麻将有没有挂”话题很是火热,小编也是针对友乐广西麻将作*弊开挂的方法以及开挂对...
最新引进“中州游戏.有挂吗?”... 有 亲,根据资深记者爆料中州游戏是可以开挂的,确实有挂(咨询软件无需打开...
重磅消息“越乡游义乌麻将.开挂... 有 亲,根据资深记者爆料越乡游义乌麻将是可以开挂的,确实有挂(咨询软件无...
玩家最新攻略“全民游戏.辅助器... 玩家最新攻略“全民游戏.辅助器?”必胜开挂神器您好,全民游戏这个游戏其实有挂的,确实是有挂的,需要了...
我来教教您“聚友.有挂吗?”外... 家人们!今天小编来为大家解答聚友透视挂怎么安装这个问题咨询软件客服徽4282891的挂在哪里买很多人...
【第一消息】“毛豆大厅炸金花.... 网上科普关于“毛豆大厅炸金花有没有挂”话题很是火热,小编也是针对毛豆大厅炸金花作*弊开挂的方法以及开...
今日重大通报“上海滩.到底有挂... 今日重大通报“上海滩.到底有挂吗?”必胜开挂神器您好,上海滩这个游戏其实有挂的,确实是有挂的,需要了...
【第一消息】“约约麻将.到底是... 您好:约约麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【9752949】很多玩家在这款游戏...