第十五章 进程池和线程池
前面章节中我们是通过动态创建子进程或子线程来实现并发服务器的. 这样有如下缺点:
- 动态创建进程(或线程)是比较耗费时间的,这将导致较慢的客户响应。
- 动态创建的子进程(或子线程)通常只用来为一个客户服务(除非我们做特殊的处理),这将导致系统上产生大量的细微进程(或线程)。进程(或线程)间的切换将消耗大量CPU时间。
- 动态创建的子进程是当前进程的完整映像。当前进程必须谨慎地管理其分配的文件描述符和堆内存等系统资源,否则子进程可能复制这些资源,从而使系统的可用资源急剧下降,进而影响服务器的性能。
15.1 进程池与线程池概述
进程池中所有的子进程都运行着相同的代码, 并拥有相同的属性, 如优先级, PGID等. 由于进程池在服务器启动之初就创建好了, 所以每个子进程都相对干净, 即它们没有打开不必要的文件描述符或大块的堆内存.
当有新的任务到来时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务。相比于动态创建子进程,选择一个已经存在的子进程的代价显然要小得多。至于主进程选择哪个子进程来为新任务服务,则有两种方式:
- 主进程使用某种算法来主动选择子进程。最简单、最常用的算法是随机算法和Roud Robin(轮流选取)算法,但更优秀、更智能的算法将使任务在各个工作进程中更均匀地分配,从而减轻服务器的整体压力。
- 主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。当有新的任务到来时,主进程将任务添加到工作队列中。这将唤醒正在等待任务的子进程,不过只有一个子进程将获得新任务的“接管权”,它可以从工作队列中取出任务并执行之,而其他子进程将继续睡眠在工作队列上。
15.2 处理多客户
在使用进程池处理多客户任务时, 首先要确认的问题是: 监听socket和连接socket是否都由主进程来统一管理.
一个客户的多次请求可以复用一个TCP连接, 因此在设计进程池时还需要考虑: 一个客户连接上的所有任务是否始终由一个子进程来处理. 如果客户任务是无状态的, 可以考虑使用不同的子进程来为该客户的不同请求服务, 如图. 但如果任务是存在上下文的, 则最好一直用一个子进程来为之服务.
15.3 半同步/半异步进程池实现
15.4 用进程池实现的简单CGI服务器
15.5 半同步/半反应堆线程池实现
15.6 用线程池实现的简单Web服务器
- Title: 第十五章 进程池和线程池
- Author: Huan Lee
- Created at : 2023-08-20 08:08:15
- Updated at : 2024-02-26 04:53:15
- Link: https://www.mirthfullee.com/2023/08/20/notion-第十五章 进程池和线程池-e3dae320/
- License: This work is licensed under CC BY-NC-SA 4.0.