什么是进程,线程和协程

一、进程、线程和协程的详细解释#

🟠 1. 进程(Process)#

  • 定义:

    • 进程是操作系统中分配资源的最小单位,每个进程都有自己独立的内存空间、文件描述符、堆栈等资源。
    • 进程之间相互独立,数据无法共享,通信需要依赖 IPC(进程间通信机制)。
  • 特点:

    • 独立性: 每个进程有独立的内存空间,互不干扰。
    • 资源消耗大: 创建、销毁进程需要较高的资源开销。
    • 上下文切换慢: 由于进程间隔离性强,切换时需要保存和恢复大量状态信息,涉及内核态与用户态切换,开销大。
    • 稳定性高: 一个进程崩溃不会影响其他进程。
  • 应用场景:

    • 适合 CPU 密集型任务,如图像处理、视频编解码。
    • Web 服务器(如 NGINX、Apache),每个请求可由单独进程处理。
    • PHP-FPM 模式中,每个请求对应一个独立进程。

🔵 2. 线程(Thread)#

  • 定义:

    • 线程是 CPU 调度的最小单位,属于进程的一部分。
    • 一个进程可以包含多个线程,它们共享进程的资源(如内存空间、全局变量),但有独立的堆栈和寄存器。
  • 特点:

    • 共享内存: 同一进程内的线程共享内存,通信成本低。
    • 切换成本低: 线程切换开销比进程小,但仍需内核态和用户态切换。
    • 数据共享: 线程之间可以共享数据,但要注意同步问题,防止竞争条件。
    • 多线程并发: 多线程适合在多核 CPU 上并行处理,提高执行效率。
  • 应用场景:

    • 适合 计算密集型任务,如数据计算、并行处理。
    • PHP 中的 pthreads 扩展可以实现多线程。
    • Go 语言中的 Goroutine 本质上是协程,但底层由多线程调度执行。
    • Web 服务器处理多个用户请求时,通过线程池复用。

🟢 3. 协程(Coroutine)#

  • 定义:

    • 协程是一种用户态的轻量级线程,由用户自行调度,不依赖操作系统内核。
    • 本质上是一个可以在函数之间主动挂起和恢复的控制流机制。
    • 切换速度比线程更快,因为它不涉及内核态切换,仅在用户态切换。
  • 特点:

    • 轻量级: 一个线程可以承载成千上万个协程,极大提高并发能力。
    • 非抢占式调度: 协程由用户手动调度,而不是由操作系统决定。
    • 适合 IO 密集型: 适用于网络请求、爬虫、异步 IO 等任务。
    • 切换效率高: 协程切换只需保存少量寄存器信息,速度远快于线程。
  • 应用场景:

    • IO 密集型任务,如爬虫、网络请求、异步编程。
    • PHP 中的 Swoole、Hyperf 框架使用协程实现高并发处理。
    • Go 语言中的 Goroutine 实现协程并发,底层自动映射到内核线程。

二、三者的通信方式#

🔹 1. 进程间通信(IPC)#

由于进程之间彼此独立,通信必须依靠操作系统提供的 IPC 机制:

  • 管道(Pipe): 父子进程通信,半双工。
  • 消息队列: 使用消息队列在进程之间传递数据。
  • 共享内存: 多个进程可以映射到同一块内存区域。
  • 信号量: 用于同步进程。
  • 套接字(Socket): 跨主机或进程通信。

🛠️ PHP 示例:使用 socket 通信

// 父进程监听 socket 端口,子进程发送消息
$socket = stream_socket_server("tcp://127.0.0.1:12345");
while ($conn = stream_socket_accept($socket)) {
    fwrite($conn, "Hello from Parent Process\n");
    fclose($conn);
}
fclose($socket);

🔹 2. 线程间通信#

线程之间共享内存,可以直接访问公共变量,但需要注意同步问题:

  • 互斥锁(Mutex): 防止多个线程同时访问共享资源。
  • 读写锁(RWLock): 分别控制读和写。
  • 条件变量: 用于线程同步。

🛠️ PHP 示例:多线程通信

// 线程共享内存
$thread = new class extends Thread {
    public function run() {
        echo "Thread running\n";
    }
};
$thread->start();
$thread->join();
echo "Main thread done\n";

🔹 3. 协程通信#

协程间通信方式:

  • Channel 通信: 类似队列,协程之间通过 Channel 通信。
  • 异步通信: 使用异步回调实现非阻塞通信。
  • 消息队列: 多协程写入、读取队列。

🛠️ PHP 示例:Swoole 协程 Channel

use Swoole\Coroutine;
use Swoole\Coroutine\Channel;

go(function () {
    $chan = new Channel(1);
    $chan->push("Hello Coroutine");
    echo "Message sent\n";
});

go(function () {
    $chan = new Channel(1);
    echo $chan->pop();
});

三、PHP 中的应用#

在 PHP 中,协程可以通过 Swoole 和 Hyperf 实现高并发:

  • Swoole: 提供基于协程的异步编程能力,支持 TCP、UDP、WebSocket 等协议。
  • Hyperf: 基于 Swoole 实现,提供更完善的框架,适合微服务架构。
  • Workerman: 基于 PHP 多进程模型,适合长连接、实时推送等场景。

四、总结回答示例#

面试官:什么是进程、线程和协程?它们有何区别?

回答示例:

进程 是操作系统分配资源的最小单位,拥有独立的内存空间,切换开销大,适合 CPU 密集型任务。
线程 是进程内的执行单元,多个线程共享内存,切换开销较小,适合多线程计算任务。
协程 是用户态的轻量级线程,切换速度快,适合 IO 密集型任务,比如爬虫、网络请求。
三者通信方式不同:进程通过 IPC 通信,线程共享内存通信,协程使用 Channel 通信。
在 PHP 中,Swoole 和 Hyperf 框架使用协程实现高并发处理,比如 Web 服务和爬虫等场景。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 4

Swoole 协程 Channel 示例是错的,老弟,通道要放在外面去,都是局部通道,如何通信?

2周前 评论
梦想星辰大海 2周前
Abyan 2周前
Anoxia (作者) 2周前