php 进程 线程 协程


并行 parallellism,并发 concurrency
解释一 并行 两个或者多个事件在 同一时刻发生 而 并发 是指两个或多个事件在 同一 时间间隔 发生
解释二 并行 在 不同实体上 的多个事件 并发是在 同一实体上 的多个事件
解释三 在一台处理器上 同时 处理多个任务 在 多台处理器上 同时处理多个任务 如hadoop分布式集群
并发的关键 是 一个处理器上有处理多个任务的能力 不一定要同时
并行的关键 是 在多个不同的处理器上 同时处理多个任务的能力
最关键的点就是 是否是 同时

进程

一个程序在一个数据集上的一次动态执行过程
进程 由程序 数据集 进程控制块 三部分组成
程序   描述进程要完成哪些功能以及如何完成
数据集 程序在执行过程中所需要使用的资源
进程控制块 用来记录进程的外部特征 描述进程的执行变化过程 系统 利用它来控制和管理进程 是系统感知进程存在的唯一标志
进程 是具有一定独立功能的程序在关于某个数据集合上的一次 运行活动
进程是系统进行资源分配和调度的一个独立单位

线程

轻量级进程 是一个基本的CPU执行单元 也是程序执行过程中的最小单元
由线程ID 程序计数器 寄存器集合 和 堆栈共同组成
线程的引入减小了程序并发执行时的开销 提高了操作系统的并发性能 线程没有自己的系统资源
线程 较之 进程 优势在于 快 不管是创建新的线程还是终止一个线程
不管是 线程间的切换还是线程间共享数据或通信 其速度与进程相比都有较大的优势
线程 是为了降低上下文切换的消耗 提高系统的并发性 并突破一个进程只能干一样事的缺陷 使到进程内并发成为可能
进程与线程的区别
每个进程 有一个 进程控制块 和 用户地址空间
每个线程 有一个 独立的栈 和 独立的控制块 都有自己一个独立执行上下文
线程 在执行过程中 与 进程 不同
每个独立的线程有一个程序运行的入口 顺序执行序列 和 程序的出口
线程不能够独立执行 必须依存在于进程之中 由进程提供多个线程执行控制
逻辑角度 看 多线程的意义在于一个进程中 有多个执行部分可以同时执行  此时 进程本身不是基本运行单位 而是线程的容器
1 进程资源的分配 和 调度的 独立单元 而线程是 CPU调度的基本单元
2 同一进程包括多个线程 且线程共享整个进程的资源(寄存器 堆栈 上下文) 线程只能属于一个进程 而一个进程有多个线程,一个进程至少包括一个线程
3 进程创建用fork 或vfork,线程创建调用 pthread_create 进程结束后它拥有的所有线程都将销毁 而线程的结束不会影响同个进程中的其他线程的结束
4 线程是轻量级的进程 创建和销毁所需要的时间比进程小很多 CPU分给线程 即真正在CPU上运行的是线程
5 线程执行时一般都要进行 同步和互斥 因为他们共享同一进程的所有资源
6 线程有自己的私有属性TCB 线程id 寄存器,硬件上下文 ,进程有自己的私有属性进程控制块PCB 私有属性不被共享,用来标示一个进程或一个线程的标志

多进程 与 多线程对比

多进程 和 多线程 明显的模型区别 在处理请求时的逻辑
在多进程情况下 由于跨进程 不好传递fd连接 那么多进程通常采用在父进程中listen() 
然后各个子进程accept()的方式来实现负载均衡 这样的模型下可能会有惊群的问题
而多线程模型下 可以采用一个独立线程接受请求然后派发到各个 worker线程的方式

内核态的线程

内核态的线程是由操作系统调度,在切换线程上下文要先保存上一个线程的上下文,
执行下一个线程,当条件满足时 切换回上一个线程 并恢复上下文

协程

是用户态的线程,协程 类似 内核态的线程  用户态的线程不是由操作系统来调度的 而是由程序员来调度的 是在用户态的
yield 关键字 是用来产生中断 并保存当前的上下文的 比如说程序的一段代码是访问远程服务器 那这个时候CPU就是空闲的,
就用yield让出CPU 接着执行下一段的代码 如果下一段代码还是访问除CPU以外的其它资源,
还可以调用yield让出CPU 继续往下执行 这样就可以用同步的方式写异步的代码了
协程的出现
协程出现之前 要实现多任务并发 在无 操作系统OS 时代 可以使用状态机的思想对多任务进行拆解 在单进程环境中运行多任务 但是这种模式下需要开发者对每个任务有清晰的了解 也要开发者自行开发与任务相关功能(如任务间的通讯)
操作系统OS 出现 就开始使用OS提供的 进程和线程功能 来轻易实现多任务 在OS中 上下文切换是 OS内核控制
但是后来却出现了一个问题 频繁的进程上下文切换导致了OS性能的降低(主要是短时执行消耗小的任务进程)
为了解决这个问题 开始提出 在同一进程或线程中运行多个任务 这种问题就相当于回到了早期的无OS时代的多任务实现 而现在解决方案称为 协程
其本质是  将任务切换的部分工作从 内核转移到应用层
php 协程的基本工具 以及 基本使用
要实现协程 php 出了两个 东西 生成器 和 yield关键字

什么是生成器

生成器 继承了 实现了 迭代器 在php代码中和函数的定义类似 不过内部使用了 yield关键字
function gen(){
  echo "我刚来".PHP_EOL;//step1
  $ret=(yield "gen1");//step2
  echo "执行1\n";
  var_dump($ret);//step3
  echo "执行2\n";
  $ret=(yield "gen2");//step4
  var_dump($ret);//step5
  echo "执行3\n";  
}
echo "1\n";
$my_gen=gen();
echo "2\n";
var_dump($my_gen->current());
echo "3\n";
var_dump($my_gen->send('zjx'));
echo "4\n";
$my_gen->send('xml');


PHP 并发模型

PHP支持多线程的模型  在多线程情况下 要解 决资源共享 和 隔离的问题 PHP本身是 线程安全的
是哪种模型需要看使用的是哪个 SAPI 比如说在 Apache 中 那么就可能使用 多线程模型  也可能使用 多进程模型 而php-fpm使用的 是 多进程模型
比较推荐的方式是 使用php-fpm的模型 因为这个模型对于PHP来说有诸多的优势
.内存释放简单 使用多进程模型时进程可以容易通过退出的方式来释放内存  PHP 非常多的扩展 稍有不慎就可能导致内存泄露 fpm通过进程退出方式 简单粗暴的解决了问题
.容灾能力强 同样的问题 扩展或者php可能会出现错误 如果是 单进程 多线程模型  那么整个PHP就挂掉了 这会影响服务 多进程的话 某个进程死掉了也不会影响整体的服务
.多进程有多进程的优势 多线程也有多线程的优势 比如 HHVM 选择 多线程模型  多线程模型最大的好处是信息共享和通信方便 因为在同一个进程空间内 可以直接使用指针

PHP 进程线程协程和processthread相关