多进程并发和多线程并发
并发是指在单个CPU核心上,通过快速切换任务,使得多个任务看起来像在同时进行。 并行是指在多个CPU核心上,多个任务真正在物理上同时进行。
这两种都是经典的并发服务器设计模式,它们的核心目标相同:同时处理多个客户端请求, 实现并发处理, 提高服务器的吞吐量和响应速度。
| 特性维度 | 多进程模型 (Fork) | 多线程模型 (Pthread) |
|---|---|---|
| 基本单元 | 进程 (Process) | 线程 (Thread) |
| 资源开销 | 高。创建进程是重型操作,内存和CPU开销大,切换慢。 | 低。创建线程是轻型操作,资源占用少,切换快。 |
| 数据共享与通信 | 困难。进程地址空间独立,通信需借助IPC(管道、共享内存等)。 | 简单。所有线程共享同一地址空间(全局变量、堆、静态变量等)。 |
| 稳定性与隔离性 | 高。一个子进程崩溃不会影响父进程或其他子进程。 | 低。任何一个线程的非法操作都可能导致整个进程崩溃。 |
| 文件描述符 | 独立。fork后父子进程各有独立的文件描述符表。 | 共享。所有线程共享同一张文件描述符表,一个线程关闭会影响所有线程。 |
| 编程模型与挑战 | 编程相对简单,主要挑战在于进程间通信(IPC)的实现。 | 编程更复杂,主要挑战在于处理线程安全和数据同步(如互斥锁)。 |
| 并发能力 | 受限于系统进程数上限,通常只能支持几百个并发连接。 | 理论上可支持成千上万个并发连接,是高并发服务器的主流选择。 |
多进程并发
多进程并发服务器模型通过创建多个子进程来处理客户端请求。每当有新的客户端连接时,服务器会调用 fork() 系统调用创建一个新的子进程,这个子进程专门负责与该客户端进行通信和处理请求。父进程继续监听新的连接请求。
基本流程如下:
- 服务器启动,创建一个监听套接字 (listening socket),绑定到指定端口,并开始监听连接请求。
- 当有新的客户端连接时,服务器调用 fork() 创建一个新的子进程
- 子进程继承父进程的资源(如文件描述符),并专门处理该客户端的请求。
- 父进程继续监听新的连接请求,重复上述过程。
- 子进程处理完客户端请求后,关闭连接并退出。
- 父进程通过 wait() 或 waitpid() 回收子进程资源,防止僵尸进程(这里可以使用信号处理 SIGCHLD 来自动回收)。
示例代码:
1 |
|
多线程并发
多线程并发服务器模型通过创建多个线程来处理客户端请求。每当有新的客户端连接时,服务器会创建一个新的线程,这个线程专门负责与该客户端进行通信和处理请求。主线程继续监听新的连接请求。
基本流程如下: 1. 服务器启动,创建一个监听套接字 (listening socket),绑定到指定端口,并开始监听连接请求。 2. 当有新的客户端连接时,服务器创建一个新的线程,这个线程专门处理该客户端的请求 3. 主线程继续监听新的连接请求,重复上述过程。
1 |
|
线程池和任务队列
线程池是一种预先创建一定数量线程的技术,这些线程在需要时可以被重复使用来处理多个任务,从而避免了频繁创建和销毁线程的开销。任务队列则是一个线程安全的数据结构,用于存储待处理的任务,工作线程从中取出任务并执行。