Python进程
多道技术
- 1.空间上的复用
- 例如:多个程序共用一套计算机硬件
- 2.时间上的复用
- 例如:洗衣30s,洗衣服50s,烧水30s
- 单道需要110s,多道只需要任务最长的时间
- 并发:看起来像同时进行
- 做任务A10s,做任务B10s,看起来任务A和任务B是同时进行的
- 并行:实际上同时进行
- 两个人同时做任务A,任务B
进程:
- 程序与进程的区别
- 程序就是一堆躺在硬盘上的代码,是“死的”
- 进程则表示程序正在执行的过程,是”活的“ - 是系统机型资源分配和调度的基本单位,进程也就是正在运行的程序实例
进程调度
- 先来先服务调度算法
- 一种非抢占式的算法,先进入就绪队列的进程,先分配处理机运行。一旦一个进程占有了处理机,它就一直运行下去,直到该进程完成工作或者因为等待某事件发生而不能继续运行时才释放处理机
- 对长作业也有利,对短作业无利
- 短作业有限调度算法
- 以作业的长短来计算优先级,作业越短,其优先级越高。作业的长短是以作业所要求的运行时间来衡量的。在把短作业优先调度算法用于作业调度时,它将从外存的作业后备队列中选择若干个估计运行时间最短的作业,优先将它们调入内存运行。
- 对短作业有利,对长作业无利
- 时间片轮转法+多级反馈队列
- 将一个较小时间单元定义为时间量或时间片。时间片的大小通常为 10~100ms。就绪队列作为循环队列。CPU 调度程序循环整个就绪队列,为每个进程分配不超过一个时间片的 CPU。
- 每个进程被分配一个时间段,称作它的时间片,也就是将固定时间分成若干份,即为进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。
进程的三状态图

#程序在开始运行之后,并不是立即开始执行代码,而是会进入就绪状态,等待操作系统调度开始
import time
print("程序开始运行")
#在这里遇到等待用户输入操作,程序进入到阻塞状态
name = input("输入")
#用户输入之后进程不是立即执行而是进入就绪状态,等待操作系统的调度继续运行
print(name) #运行
#就绪
print("程序结束运行")#运行
#结束
在所有的程序运行中都会先进入到就绪状态,等待计算机的调度开始运行,如果遇到IO操作,则进入阻塞状态,进入阻塞状态后等待IO操作结束后,再次进入就绪状态等待计算机的调度运行,只有在时间片到的情况下,才会从运行状态进入到就绪状态
同步和异步
- 定义:描述的是程序的提交方式(消息的通信机制)
- 区别:
- 同步:任务提交之后,原地等待任务的返回结果,等待的过程中不做任何事,也就是等待结果之后才能继续往后执行
- 异步:任务提交之后,不再等待任务,继续完成其他的任务,等待任务的返回结果后,任务的返回结果会有异步回调函数来提醒调用者
在上面的代码中我们可以看到,程序运行时会先调用函数,在函数执行完毕之后,再去执行下面的代码,结果应该是3秒之后再执行print代码,如果是异步执行,调用之后,直接就执行print代码def func() time.sleep(3) print("任务已提交") res = func() #同步执行 print("执行")
阻塞和非阻塞
- 定义:程序在等待调用结果(消息,返回值)时的状态
- 区别:
-
阻塞:调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回
-
非阻塞:在不能立刻得到结果之前,该调用不会阻塞当前线程。
-
假如一个公司去招聘,我去面试,面试官让我回家等结果,会发生以下几种状况
同步和异步在于我,阻塞和非阻塞在于面试官
1.同步阻塞:我在公司通道等待面试官结果,不告诉结果的时候我不能干别的事,我面试官也不能进行其他面试
2.同步非阻塞:我在公司等消息,不告诉我结果,面试官也可以告诉我消息
3.异步阻塞:我在公司通道玩手机,睡觉,吃饭,但是面试官不能进行其他面试
4.异步非阻塞:我在家玩手机,睡觉,吃饭,等面试官电话通知,面试官可以进行其他面试
开启进程的两种方式
- 方法一
# 第一种
from multiprocessing import Process
import time
def func(name):
print("线程执行{0}".format(name))
time.sleep(3)
print("线程执行结束{0}".format(name))
if __name__ == '__main__':
# 创建进程对象
p = Process(target=func, args=("aaa",))
# 开启进程
p.start() # 告诉操作系统帮你创建一个进程 异步
print("主进程")
>> 主进程
>> 线程执行aaa
>> 线程执行结束aaa
- 第二种
# 第二种方法
from multiprocessing import Process
import time
# 利用类继承的方式开启进程
class Myprocess(Process): # 继承父类Process
def run(self):
print("线程执行")
time.sleep(3)
print("线程执行结束")
if __name__ == '__main__':
p = Myprocess()
p.start()
print("主进程")
- 创建进程就是在内存中申请一块内存空间,将需要运行的代码丢进去,一个进程对应在内存中就是一块肚里的内存空间
- 多进程对应在内存中就是多块的内存空间
- 进程与进程之间数据默认情况是无法直接交互,如果想交互可以借助第三方工具,模块
join方法
- 定义:join会一直阻塞到所有子进程执行结束
from multiprocessing import Process
import time
def func(name):
print("线程执行{0}".format(name))
#生成一个在0,5之间的随机数
s = random.randint(0, 5)
time.sleep(s)
print("线程执行结束{0}".format(name))
if __name__ == '__main__':
# 创建进程对象
for i in range(10):
p = Process(target=func, args=("aaa",))
p.start()#开启10个进程
p.join()
print("主进程")
#最后的结果执行是所有进程执行完毕之后再执行的主进程
进程间数据相互隔离
- 在创建一个进程的时候,计算机会在内存中开辟一个属于他自己的内存空间,在进程的内存空间中修改的数据,是不与主进程与其他进程进行共享的,是自己独有的内存空间
num = 100
def func(i):
global num
num = random.randint(0, 100) # 将num赋值为随机数,确保在两次进程运行中看到不同效果
print("进程{0}".format(i))
print(num) # 打印出进程中num
if __name__ == '__main__':
for i in range(0, 2):
p = Process(target=func, args=(i,))
p.start()
p.join() # 加入join确保被执行到
print(num) # 打印出num看是否被进程修改
进程对象及其他方法
-
current_process().pid:查看当前进程的进程号
-
os.getpid():查看当前进程的进程号
-
os.getppid():查看当前进程的父进程号
用os方法需导入os模块
-
进程对象.terminate():杀死当前进程
-
进程对象.is_alive():查看当前进程是否存活
僵尸进程和孤儿进程
- 僵尸进程:一个进程创建子进程后,子进程死后不会立刻释放占用的进程后,因为我们要让父进程能够查看到子进程的运行状态,如果一直创建僵尸进程,会大量占用计算机大量的进程号
- 孤儿进程:一个父进程意外死亡,而他的一个或者多个子进程还在运行,那么这些子进程就会成为孤儿进程。孤儿进程将被(进程号为1)所收养,并由1进程对它们完成状态收集工作。
守护进程
- 进程对象.daemon = TRUE:将进程对象设置为守护进程,这一句一定要放在start方法上面才有效,否则会直接报错
def func():
print("进程活着")
print("进程死亡")
if __name__ == '__main__':
p = Process(target=func,)
#将p这个子线程设置为守护进程
p.daemon = True
p.start()
print("主进程")
互斥锁
- 当多个进程几乎同时修改某一个共享数据的时候,需要进行同步控制。线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁
- 针对上述问题,解决方式就是加锁处理:将并发变成串行,牺牲效率但是保证了数据的安全
进程间通信
- 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信
生产者消费者模型
- 生产者:生产/制造东西的
- 消费者:消费/处理东西的
该模型除了上述两个之外还需要一个媒介:生活中的例子做包子的将包子做好之后放入到蒸笼(媒介)里面,买包子的去蒸笼里面拿,厨师做完菜之后用盘子装好端过去,生产者和消费者之间不是直接做交互的,而是借助于媒介做交互