两种高效处理事件的方式/线程池
服务器程序通常需要处理三类事件:I/O 事件、信号及定时事件。有两种高效的事件处理模式:Reactor和 Proactor,同步 I/O 模型通常用于实现 Reactor 模式,异步 I/O 模型通常用于实现 Proactor 模式。
Reactor
要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生,有的话就立即将该事件通知工作线程(逻辑单元),将 socket 可读可写事件放入请求队列,交给工作线程处理。除此之外,主线程不做任何其他实质性的工作。读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。
reactor工作流程

Proactor模式
Proactor 模式将所有 I/O 操作都交给主线程和内核来处理(进行读、写),工作线程仅仅负责业务逻辑。使用异步 I/O 模型(以 aio_read 和 aio_write 为例)实现的 Proactor 模式的工作流程是:

模拟Proactor模式


半同步/半异步模式
线程池
提高服务器性能的很直接的方法就是以空间换时间,即浪费服务器的硬件资源,以换取其运行效率  这就是池的概念。
池中的资源是预先静态分配的,我们无法预期应该分配多少资源,如何解决这一问题呢?
2种方法:1.预先分配“足够多”的资源,即针对每个可能的客户链接都分配必要的资源。
2. 预先分配一些资源,不够的话再动态分配一些加入池中。
池分很多种
进程池和线程池都是并发编程的常用伎俩,当需要一个工作线程或工作进程来处理客户端请求时,我们可以直接从线程池或者进程池中取得一个执行实体,无须动态的调用fork或者pthread_create等函数来创建进程或者进程
内存池用于Socket的接受缓存和发送缓存
线程池是由服务器预先创建的一组子线程,线程池中的线程数量应该和 CPU 数量差不多 相比于动态的创建,选择一个已经存在的子线程的代价显然要小得多
主线程和所有子线程通过一个共享的工作队列来同步,子线程都睡眠在该工作队列上。当有新的任务到来时,主线程将任务添加到工作队列中。这将唤醒正在等待任务的子线程,不过只有一个子线程将获得新任务的”接管权“,它可以从工作队列中取出任务并执行之,而其他子线程将继续睡眠在工作队列上。

线程池中的线程数量最直接的限制因素是中央处理器(CPU)的处理器(processors/cores)的数量
N :如果你的CPU是4-cores的,对于CPU密集型的任务(如视频剪辑等消耗CPU计算资源的任务)来
说,那线程池中的线程数量最好也设置为4(或者+1防止其他因素造成的线程阻塞);对于IO密集
型的任务,一般要多于CPU的核数,因为线程间竞争的不是CPU的计算资源而是IO,IO的处理一
般较慢,多于cores数的线程将为CPU争取更多的任务,不至在线程处理IO的过程造成CPU空闲导
致资源浪费。
池是一组资源的集合,在服务器启动之初就已经就被完全创建好并初始化,这称为静态资源。直接从池中获取无需动态分配,使用完后,可以把相关资源放回池中,无需执行系统调用释放资源。
线程池,好东西啊,它有一池子的线程,所以叫线程池。
为什么说它是好东西呢?有的人会觉得,那一池子线程,放在那边又不用,不浪费资源?
其实这笔账很好算的:假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
当 T1+T3 > T2 && 这种线程被多次调度的时候,你还会觉得浪费资源吗?况且线程池内部又不是缺乏管理,相反,线程池内部管理很严格,吃白饭的线程很难有立足之地,用不上就裁员呗。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
原文链接:https://blog.csdn.net/qq_43762191/article/details/106882225
                    
                
                
            
        
浙公网安备 33010602011771号