首先,我们呢需要了解什么是进程呢?
狭义:进程就是正在进行的程序
广义:是操作系统分配的基本单位
程序:是一个没有生命的实体,等待处理器赋予生命,一旦程序有了生命就变成进程了。
程序和进程的区别:
1、程序是指令和数据的有序集合,其本身没有任何含义,是一个静态的资源。
进程是程序在系统中的一次执行过程。
2、程序可以作为软件长期存在,进程是有一定的生命周期的。
进程三状态:
就绪态:运行的条件都已经满足,正在等待CPU执行 执行态:CPU正在执行器功能 等待态:等待某些条件满足
有了对进程的初步了解,那么怎样创建一个进程呢?
import time
# 导包
import multiprocessing
def test1():
while True:
print("大*")
time.sleep(1)
def test2():
while True:
print("小胖手")
time.sleep(1)
# 定义一个主函数来分别执行2个进程的代码
def main():
# 分别创建test1、test2 2个进程 target的值代表要执行的进程
p1 = multiprocessing.Process(target=test1)
p2 = multiprocessing.Process(target=test2)
# 启动p1和p2
p1.start()
p2.start()
# 程序入口 常规写法:
if __name__ == "__main__":
main()
在这里,我们引入一个概念,并行与并发
我们举个例子,比如我们两个人在吃午饭。你在吃饭的整个过程中,吃了米饭、吃了蔬菜、吃了牛肉。吃米饭、吃蔬菜、吃牛肉这三件事其实就是并发执行的。对于你来说,整个过程中看似是同时完成的的。但其实你是在吃不同的东西之间来回切换的。
还是我们两个人吃午饭。在吃饭过程中,你吃了米饭、蔬菜、牛肉。我也吃了米饭、蔬菜和牛肉。我们两个人之间的吃饭就是并行的。两个人之间可以在同一时间点一起吃牛肉,或者一个吃牛肉,一个吃蔬菜。之间是互不影响的。
看到这里,是不是还是有点迷茫呢?我们再来看一张图,直观感受一下两者的区别
以上可以看出,
并行:同一时刻,多个任务同时执行
并发:同一时间,多个任务同时执行
并行与并发的区别:
微观上:并行是指同一时间点上,多个任务真正同时执行
宏观上:并发是指在一个时间段内,多个任务走走停停
有进程,当然就有子进程,我们代码实现一下吧!
# 导包
# import time
# from multiprocessing import Process
# 创建函数--子进程
def work1():
while True:
print("我是子进程嘻嘻嘻")
time.sleep(1)
# 程序入口
if __name__ == "__main__":
# 创建子进程对象
p1 = Process(target=work1)
# 启动
p1.start()
while True:
print("我是主进程,哈哈哈")
time.sleep(1)
深入了解process 参数说明: target:如果传递了函数的引用,就可以认为要执行该子进程的代码 args:给target指定的函数传递参数,参数以元组的形式传递,如果元组中只有一个值,需要加逗号 kwargs:给target指定的函数传递参数,参数以字典的形式传递 name:给进程起名字 group:指定进程组
import time
from multiprocessing import Process
# 创建函数--子进程
def work1(*args,**kwargs):
while True:
print(args)
print(kwargs)
time.sleep(1)
# 程序入口
if __name__ == "__main__":
# 创建子进程对象
p1 = Process(target=work1,args=("大木",19),kwargs={"性别":"男"})
# 启动
p1.start()
while True:
print("大木二货,哈哈哈")
time.sleep(1)
说明:1、右键run的时候就会创建一个进程,这个进程就称为主进程 2、在程序中创建的work1为子进程 3、创建进程和启动进程时需要使用target参数和start()方法 4、根据题意来判断需不需要在process里传args和kwargs参数 注意:必须写程序入口
Process创建实例对象的常用方法: start:启动子进程 terminate:不管认为是否完成,立即终止子进程 join([timeout]):是否等待子进程结束之后,再执行主进程,或等待多少秒 is_alive:判断子进程是否还活着 Process创建实例对象的常用属性: name:进程名字 pid:进程的id--pid multiprocessing是一个模块
现在我们已经基本了解了进程,那么进程间是如何实现通信的呢?
# 进程间数据的隔离性
# 定义一个全局变量 列表
lst = [11,22]
# 导包
import multiprocessing
import time
# 第一个进程 向列表中添加数据
def work1():
for i in range(3):
lst.append(i)
time.sleep(1)
print(lst)
# 第二个进程对列表不做任何改变
def work2():
print(lst)
# 程序入口
if __name__ == '__main__':
p1 = multiprocessing.Process(target=work1)
p1.start()
# join([timeout]):是否等待子进程结束之后,再执行主进程,或等待多少秒
# 让p1这个进程执行完再执行p2
p1.join()
p2 = multiprocessing.Process(target=work2)
p2.start()
# 输出结果:[11, 22, 0]
# [11, 22, 0, 1]
# [11, 22, 0, 1, 2] 进程1操作之后的结果
# [11, 22] 进程2操作之后的结果
# 总结:进程间数据具有隔离性,进程之间不能共享全局变量
队列:一种数据结构 特点:先进先出 当存满数据再次存储会出现阻塞的状况 当数据已经全部取完,再继续取数据也会出现阻塞
import multiprocessing
ret = multiprocessing.Queue(3) #该队列有3个值
#存数据 put
ret.put(11)
ret.put("22")
ret.put({"小明":"白白胖胖"})
# 检测是否为满
# print(ret.full())
# 检测是否为空
# print(ret.empty())
# 取数据 get
print(ret.get()) #11
print(ret.get()) #22
print(ret.get()) #[11,22]
# print(ret.get()) #阻塞
# get_nowait以异常的方式告诉我们已经取完数据了
print(ret.get_nowait())
接下来,我们一起了解一下进程池!
进程池:需要创建多个进程比如成千上万个进程时,如果使用Process手动创建非常费时间
同步与异步:是提交任务的两种方式
同步:提交任务后在原地进行等待,直到任务运行完毕拿到任务的返回值才进行下一行代码
异步:提交完代码不在原地等待直接进行下一次
阻塞与非阻塞:
阻塞:程序一旦发生阻塞就会停在原地,并且立刻释放CPU资源
非阻塞:即使遇到I/O阻塞,也不会停在原地
# 定义一个池子,池子里有固定的进程数,有需求来了,
# 再进程池中加一个任务,如果任务满了则需等待
import multiprocessing
import os
import time
# 创建进程
def func(data):
print("进程%s--打印传入的参数%s" %(os.getpid(),data))
time.sleep(1)
# 程序入口:
if __name__ == '__main__':
# 创建进程池 参数代表最大进程数
po = multiprocessing.Pool(3)
for i in range(10):
# po.apply(func,args=(i,))
po.apply_async(func,args=(i,))
print("我是主进程")
po.close()
po.join()
apply和apply_async提交方式的区别: apply:同步提交 按顺序执行 apply_async:异步提交 任务都是异步
今天,我们一起学习了进程、子进程、进程间的通信以及进程池,下节我们继续学习线程,拜拜!