linux 线程池 EPOLLONESHOT事件

线程池:

线程池是由服务器预先创建的一组子线程线程池中的线程数量应该和 CPU 数量差不多。线程池中的所有子线程都运行着相同的代码。当有新的任务到来时,主线程将通过某种方式选择线程池中的某一个子线程来为之服务。相比与动态的创建子线程,选择一个已经存在的子线程的代价显然要小得多。至于主线程选择哪个子线程来为新任务服务,则有多种方式:

  🔴 主线程使用某种算法来主动选择子线程。最简单、最常用的算法是 随机算法Round Robin(轮流选取)算法,但更优秀、更智能的算法使任务在各个线程中更均匀地分配,从而减轻服务器地整体压力。

  🔴 主线程和所有子线程通过一个共享的工作队列来同步子线程都睡眠在该工作队列上。当有新的任务到来时,主线程将任务添加到工作队列中。这将唤醒正在等待任务的子线程,不过只有一个子线程将获得新任务的 “接管权” ,它可以从工作队列中取出任务并执行之,而其他子线程将继续睡眠在工作队列上。

线程池的一般模型为:

线程池中的线程数量最直接的限制因素是中央处理器(CPU)的处理器(processors/cores)的数量N:如果你的CPU是 4-cores 的,对于 CPU 密集型的任务(CPU计算型任务)(如视频剪辑等消耗 CPU 计算资源的任务)来说,那线程池中的线程数量最好也设置为 4(或者 +1 防止其他因素造成的线程阻塞);对于 IO 密集型的任务(如Web服务器),一般要多于 CPU 的核数,因为线程间竞争的不是 CPU 的计算资源而是 IO, IO的处理一般较慢,多于 cores 数的线程将为 CPU 争取更多的任务,不至于在线程处理 IO 的过程造成 CPU 空闲导致资源浪费。

  🔴 空间换时间,浪费服务器的硬件资源,换取运行效率。

  🔴 池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源。

  🔴 当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源,可以直接从池中获取,无需动态分配。

  🔴 当武器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用释放资源。

 EPOLLONESHOT事件:

  即使可以用 ET 模式,一个 socket 上的某个事件还是可能被触发多次。这在并发程序中就会引起一个问题。比如一个线程在读取完某个 socket 上的数据后开始处理这些数据,而在数据的处理过程中该 socket 上又有新数据可读(EPOLLIN 再次被触发),此时另外一个线程被唤醒来读取这些新的数据。于是就出现了两个线程同时操作一个 socket 的局面。 一个 socket 连接在任一时刻都只被一个线程处理,可以使用 epoll 的 EPOLLONESHOT 事件实现。

  对于注册了 EPOLLONESHOT 事件的文件描述符,操作系统最多触发其上注册的一个可读、可写或者异常事件,且只触发一次,除非我们使用 epoll_ctl 函数重置该文件描述符上注册的 EPOLLONESHOT 事件。这样,当一个线程在处理某个 socket 时候,其他线程是不可能有机会操作该 socket 的。但反过来思考,注册了 EPOLLONESHOT 事件的 socket 一旦被某个线程处理完毕,该线程就应该立即重置这个 socket 上的 EPOLLONESHOT 事件,以确保这个 socket 下一次可读时,其 EPOLLIN 事件能被触发,进而让其他工作线程有机会继续处理这个 socket。

posted on   廿陆  阅读(139)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示