进击のpython
并发编程——进程理论
基于上一小节,相信对计算机的操作系统的发展史有了大致的了解
那这一小节我们对以下几个方面进行展开:
1.什么是进程
2.并发与并行
3.进程创建的方式
4.进程的三种状态
什么是进程
进程,进行的程序,这是一个状态。
一个正在进行的程序或者是一个任务都可以称为进程
而执行任务的就是CPU
进程与程序有什么区别呢?程序是一个名词,就是一堆复杂的代码体,而进程就是执行程序的过程
并发与并行
其实说句题外话无论是并行还是并发,在用户看来,程序都是“同时”进行的
而对于进程还是线程来说,都是同一个任务,真正在工作的就是CPU
一个CPU在同一时刻只能做同一个任务
并发
并发其实是伪并行,看起来是同时运行的,可以通过单个CPU+多道技术来实现
就像夏天的你在空调屋,一边喝着啤酒,一边吃着炸鸡,一边追剧
那就应该是吃几口炸鸡,然后停下来,去喝啤酒,然后抬头看看韩剧
你在同一时刻只能喝啤酒或者吃炸鸡(一个CPU在同一时刻只能做同一个任务)
但是别人看上去就是在同时进行的
并行
并行才是真正的同时运行,只有具备多个CPU才能实现并行
单核下,可以利用多道技术;多核下,每个核也可以利用多道技术
现在有四核六个任务,执行顺序是怎么样的?
CPU1,CPU2,CPU3,CPU4同时执行任务1~4
当1~4某个任务遇到I/O,就被迫中断,此时任务5就来使用这个CPU
而中断任务的I/O结束了,操作系统就会重新调用(需知进程的调度、分配给哪个CPU运行,由操作系统说了算)
可能是CPU1~4的任意一个
进程的创建
是个计算机,他就得有硬件参与,有硬件参与就一定有操作系统
而由操作系统,就会有进程的概念,也就需要一个创建的方式
而像一些简单的操作系统,只服务于一个应用程序,比如扫地机器人
那对于像电脑里面的这种通用系统来说,就需要有系统运行过程中创建和销毁进程的能力
创建新的进程,总共有四种方式
- 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
- 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
- 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
- 一个批处理作业的初始化(只在大型机的批处理系统中应用)
无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:
- 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
- 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。
无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:
- 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
- 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。
关于创建的子进程,UNIX和windows
1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔 离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。
2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内 存区的。但是对于windows系统来说,从一开始父进程与子进程的地址空间就是不同的。
那有创建,就有终止,进程的终止一般有以下的几种方式
- 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
- 出错退出(自愿,python a.py中a.py不存在)
- 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try…except…)
- 被其他进程杀死(非自愿,如kill -9)
进程的三种状态
tail -f access.log |grep '404'
执行程序tail,开启一个子进程,执行程序grep,开启另外一个子进程,两个进程之间基于管道'|'通讯,将tail的结果作为grep的输入。
进程grep在等待输入(即I/O)时的状态称为阻塞,此时grep命令都无法运行
其实在两种情况下会导致一个进程在逻辑上不能运行,
1. 进程挂起是自身原因,遇到I/O阻塞,便要让出CPU让其他进程去执行,这样保证CPU一直在工作
2. 与进程无关,是操作系统层面,可能会因为一个进程占用时间过多,或者优先级等原因,而调用其他的进程去使用CPU。
因而一个进程有三种状态