# 进程
在人类刚发明计算机的时候,只能同时处理一件事情。我们通常说程序的设计来自于现实的人类世界,这个进程同样也是。
![](https://img.kancloud.cn/43/87/4387b18254baf9712ff8a882df0608aa_860x169.png)
<center>图:1.3-1</center>
图1.3-1是早期计算机的多程序执行流程,我们可以看到在一个CPU的生命周期里面,多个程序是顺序执行的。后面的程序什么时候执行取决于前面的程序什么之后执行完。如果当前执行的程序进行IO时,CPU也只能等待,CPU的使用率极低。如果当前执行的程序占用CPU时间很长,其他程序得不到CPU的执行权,只能卡着不动。
![](https://img.kancloud.cn/da/13/da13c84ef9f1907c6c0e0c5a68c7a996_847x166.png)
<center>图:1.3-2</center>
基于上面说的单进程有很多的缺点,所以出现了多道程序技术,使得程序可以并发执行。从上图可以看出来多道程序设计把CPU分成了时间片,可以在单CPU的情况下实现并发。CPU以人无法感知的速度在不停切换执行不同的程序,这样让我们看起来像是多个程序同时在执行。
![](https://img.kancloud.cn/df/36/df36b047c71539023e755e918eb06bbe_830x564.png)
<center>图:1.3-3</center>
从图1.3-3我们可以看到了每个进程有自己独立的内存、地址空间、数据栈等等,每个进程都跟其他进程互不干扰,这就是为什么有些人在写代码都时候,说定义了一个全局的属性,但是一个进程改变了,另一个进程读取却没有变化,这就是原因,每个进程有自己的独立堆栈,内存资源等。
### 进程状态
![](https://img.kancloud.cn/98/ba/98ba8053452a3fdfefe2ed912a1542b5_876x661.png)
<center>图:1.3-4</center>
在图1.3-4里面可以看到进程有不同的状态,当进程在不同状态进程处于就绪态的时候就是等待操作系统进行调度。前面我们提到过进程的切换,CPU不断的切换到不同的进程来执行,当CPU调度别的进程当前执行的进程怎么办呢?下次再调度会这个进程的之后怎么知道代码执行到哪里,都有什么数据呢?其实当CPU调度别的进程的时候,会保存当前执行进程的信息、状态,这种操作叫做上下文切换。一个进程从运行态转到休眠状态的时候,进程的现场会保存到该进程的内核栈,当这进程再次进入就运行状态的时候,CPU从这个进程的PCB内核栈读取这个现场信息恢复进程。
![](https://img.kancloud.cn/95/31/95315dd46ef25ea87c629faeb7c50bd0_1179x344.png)
<center>图:1.3-5</center>
多道程序设计把CPU执行的时间分割成了很小的时间片,由操作系统在不同状态的进程进行调度。但是在一个核心CPU一次只能处理一件事情,只是因为每次切换的时间太快了,让我们认为是一起执行的。
### 上下文切换
![](https://img.kancloud.cn/3e/ac/3eaca68fccdd72874762fddf04c70ec3_743x311.png)
<center>图:1.3-6</center>
当一个进程遇到阻塞的之后CPU就会切换到另一个进程执行,避免在在进程阻塞的时候浪费CPU资源。
> 进程不是越多越好,进程过多在上下文切换过程中浪费大量的CPU可执行时间
> 并发与并行的区别:并发是某一个时间段做多少事情,并行是同一时刻同时做多件事情
### 孤儿进程
前面说过了,计算机模拟的是人类世界,那么这个孤儿进程跟我们人类世界一样,没有父母没有监护人的为孤儿。孤儿进程产生的原因是父进程终止执行了,但是子进程依然在执行的子进程就被叫做孤儿进程。
### 僵尸进程
僵尸进程产生的原因是因为子进程终止之后父进程没有对其进行回收,子进程的进程描述符依然保留在系统当中,所以产生了僵尸进程,僵尸进程对于操作系统是有资源浪费的。所以务必避免出现僵尸进程,解决办法可以在父进程调用wait或者waitpid解决。
### 守护进程
在Linux操作系统里面我们想要实现关闭终端之后还可以运行,我们通常采用
* nohup
* setsid
* 命令后面加 &
这几种方式,我们想想在前面说过的孤儿进程好像就可以是现在这样的功能。我们只要父进程退出执行,子进程还是依然会执行的。这就是我们通过故意产生孤儿进程来实现守护进程的功能。
- 第一章:基础知识
- 课程简介
- PHP-FPM过渡常驻内存
- 进程
- 实战:实现Master-Worker
- 线程
- 实战:CC攻击器
- 协程
- 实战:实现waitGroup功能
- 进程、线程、协程的区别
- 第二章:初识Swoft2.0
- Swoft介绍
- Swoft环境安装
- gcc升级
- 安装Swoft框架
- 目录结构介绍
- SwoftCli工具
- Swoft配置
- 第三章:Swoft2.0核心
- 上下文
- 常驻内存没有上下文隔离
- 实战:手写swoole框架上下文管理
- Bean容器
- 实战:根据容器原理实现容器
- 实战:通过容器实现依赖注入
- Bean容器定义与使用
- 配置文件定义Bean
- 容器类型
- 面向接口的容器
- 注解
- 实战:实现注解
- 自定义Swoft注解类
- 事件
- 连接池
- 实战:Swoole实现连接池
- 第四章:Http服务器
- Http Server生命周期
- Http Server配置
- 控制器
- 路由
- 请求对象Request
- 响应对象Response
- Http异常处理
- 中间件
- 实战:中间件实现JWT登陆授权
- 第五章:验证器
- 内置验证类型
- 验证器的使用
- 自定义验证器
- 第六章:数据库操作
- 连接数据库
- 实体模型
- 模型事件
- 查询器
- 事务处理
- 连接池配置
- 读写分离
- 多数据库切换
- Models分层结构
- 实战:实现用户CURD API
- 第七章:Redis
- 连接redis和使用
- Redis连接池
- Redis集群配置(单机版)
- Redis集群配置(多服务器)
- Redis连接集群
- Redis实战:实现延时任务
- 第八章:AOP编程
- AOP概念
- AOP实现原理
- 实战实现AOP:静态代理
- 实战实现AOP:动态代理
- 切面注解介绍
- PointExecution切面
- PointBean切面
- PointAnnotation切面
- 实战:使用AOP实现日志记录
- 第九章:任务处理
- 进程使用
- 进程池使用
- 实战:进程消费队列
- 实战:进程实现RabbitMQ延时队列
- 异步任务
- 协程任务
- 定时任务