并发编程
并发与串行
为什么要并发(之前程序所存在的问题)
- 程序默认执行方式是串行(即程序自上而下,一行一行顺序执行,必须把当前任务执行完毕,才能开始执行下一个任务,无论当前任务需要多长时间)
- 问题举例:
- 如:TCP的服务器中,如果正在进行通讯循环,则无法处理其他的客户端请求
- 如:执行了input语句,用户不输入,则一直卡在原理
- 学习并发的目的就是要编写可以同时执行多个任务的程序,来提高效率
串行和并发都是程序处理任务的方式
实现并发的方式
- 多进程
- 多线程
- 协程
进程是什么
进程指的是正在运行中的程序,是操作系统调度以及进行资源分配的基础单位
是一个资源单位
当把一个程序从硬盘读入到内存,进程就产生了
- 多进程
- 指的是同一时间有多个程序被装入内存并执行
进程来自于操作系统,由操作系统进行调度以及资源分配
多进程的实现原理其实就是操作系统调度进程的原理
多道技术
实现原理:
1.**空间复用 **
同一时间,加载多个任务到内存中,多个进程之间内存区域需要相互隔离(这种隔离是物理隔离),其目的是为了保证数据安全
2.时间复用
操作系统会在多个进程之间做切换执行
切换任务的两种情况
-
当一个进程遇到了IO操作时会自动切换
-
当一个任务执行时间超过阈值会强制切换(时间不会太长,切换的够快用户就感受不到是串行的)
注意:在切换前必须保存状态,以便后续恢复执行。并且频繁的切换也需要消耗资源
其实当所有任务都没有IO操作时,切换执行(上下文切换)效率反而更低,但是为了保证并发执行,必须牺牲效率
简单的总结就是切换加保存
有了多道技术,计算机就可以同时并发的处理多个任务
并发编程中的重要概念
串行:自上而下顺序执行
并发:多个任务同时执行,但是本质是在多个进程之间切换执行,由于速度非常快所以感觉是同时运行
并行:是真正的同时运行,必须具备多核CPU,有几个核心就能并行几个任务,但是任务数量超过核心数时还是并发执行
以上三个概念都是用于描述处理任务的方式
阻塞:指的是程序遇到了IO操作,无法继续执行代码时的一种状态
非阻塞:指的是程序没有遇到IO操作的一个状态
input() 默认是一个阻塞的操作
我们可以用一些手段将阻塞的操作变成非阻塞的操作,例如非阻塞的socket
一个进程的三种状态
-
阻塞
-
运行
-
就绪
野指针,僵尸指针,内存泄漏
野指针:变量名没有删除
僵尸指针:变量值没有被使用但是引用计数却不为0
进程的创建和销毁(了解)
对于计算机而言,必须具备创建和销毁进程的能力
创建:
-
用户的交互式请求,鼠标双击
-
由一个正在运行的程序,调用了开启进程的接口,例如subprocess
-
一个批处理作业开始
-
系统初始化
销毁:
- 任务完成, 自愿退出
- 强制结束 taskkill(windows),kill(linux)非自愿退出
- 程序遇到了异常
- 严重错误,访问了不该访问的内存
进程和程序(了解)
程序是一堆代码放在一个文件中,通常后缀是exe,原本是储存在硬盘上的
进程是将代码从硬盘读取到内存然后执行,产生的
进程是由程序产生的
一个程序可以产生多个进程,例如qq多开,每一个进程都具备一个PID,且是唯一的
进程的层级关系(了解)
在linux中,进程具备父子关系,是一个树状结构,可以相互查找,但不能使用
当一个程序开启了另一个不属于自己管理的资源,手里握着对方的地址信息,也就是句柄
在windows中,没有层级关系,父进程可以将子进程的句柄转让
父进程 子进程?
例如qq开启了浏览器,那么qq是父进程,浏览器是子进程
PID和PPID(了解)
PID 当前进程的编号
PPID 父进程的编号
在pycharm中访问PID与PPID
import os
os.getpid()
os.getppid()
在cmd中查找程序的pid
tasklist | findstr python
注意:当我们运行Py文件时,其实运行的是python解释器进程