什么是进程
通俗点说进程就是当一个应用程序在运行的时候首先操作系统将程序装载到内存中,操作系统为它分配资源及协调其它应用,运行起来的程序就是一个进程,程序与进程对应关系,程序只有一个,但是进程可以有多个。(进程是系统进行资源和调度的基本单位)
进程的三大特征
1.动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
2.并发性:任何进程都可以同其他进行一起并发执行;
3.独立性:进程是系统进行资源分配和调度的一个独立单位;
4.结构性:进程由程序,数据和进程控制块三部分组成
进程创建
创建多进程实现多任务
#encoding:utf-8
from multiprocessing import Process
import time
def sing(): #定义函数
for i in range(3):
print("唱%d首歌"%(i+1))
time.sleep(1)
def dance(): #定义函数
for i in range(3):
print("跳%d段舞"%(i+1))
time.sleep(1)
def main():
p1 = Process(target=sing)
p2 = Process(target=dance)
p1.start() #启动进程,既让进程开始执行
p2.start()
if __name__=="__main__":
main() #主进程
结果:
以上代码执行前
执行后
首先程序运行时,程序从上往下走,遇到main()函数然后开始执行,执行mian函数的函数体时又创建了两个进程我们称之为子进程,程序运行时的线程我们称之为主进程然后子进程根据target=xxx 开始执行指定的函数体。(等子进程结束后主进程结束,程序结束了)
其实进程的创建是有分类的上面就是使用Process类创建的,还可以用Process子类创建,通过继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象,我们用代码了解一下:
from multiprocessing import Process
import time
import os
#继承process类
class Process_class(Process):
# 使用父类的初始化方法
#因为Process类本身也有__init__方法,定义这个类相当于重写这个方法
def __init__(self):
super(Process_class,self).__init__()
# 重写Porcess的run()方法
def run(self):
print("子进程(%s)开始执行,父进程(%s)" % (os.getpid(), os.getppid()))
for i in range(5):
print("--子进程%d--"%(i+1))
time.sleep(1)
if __name__ == '__main__':
p = Process_class() #创建对象
p.start() #启动进程
for i in range(5):
print("--main%d--"%(i+1))
time.sleep(1)
结果:
我们知道Process是一个类,我们每次创建都要调用它,这次我们运用一个类把它进行继承并且进行重写的方法创建一个进程。
进程的状态
进程的三态状态转换图
进程就是实现多任务的方式之一,我们通过多任务知道,多核CPU在工作的时候,所执行的任务往往大于核数,这么一来在执行的时候有些任务在执行,有些任务在等待执行,所以导致了不同的状态。
就绪态:启动的进程都已经满足运行的条件,正在等待CPU执行
执行态:就绪态的进程通过CPU的调度并在CPU执行其功能
等待态:等待条件的满足的状态,如执行有sleep的程序就要等待一会,等待信号,缓存等的状态,都是等待态
进程参数
主进程可以给子进程传递参数
import time
import multiprocessing
def work(a,b,c):
print("参数:",a,b,c)
for i in range(10):
print("正在运行子线程%d"%(i+1))
time.sleep(0.5)
if __name__ == '__main__':
#参数的传递 1.使用args传元祖 2.使用kwargs传字典 3.混合使用args和kwargs
a=multiprocessing.Process(target=work,name="f",args=(10,),kwargs={"c":100,"b":100})
# a=multiprocessing.Process(target=work,name="f",args=(10,100,1000))
# a=multiprocessing.Process(target=work,name="f",args=(10,100,1000))
a.start()
结果:
我们清晰的看到给子进程传递的方式有三种:
1.使用args传元祖
2.使用kwargs传字典
3.混合使用args传元组和kwargs传字典
进程中的全局变量共享问题
简单说我们通常用微信和浏览器,当两个程序都打开的时候就有对应的进程,如果我们这两个进程的变量共享,那么这样一来就程序混乱了,下来我们通过代码验证一下,
import multiprocessing
import time
#定义全局变量
a=10
#work1 对全局变量累加
def work1():
global a
for i in range(10):
a+=1
print("---work1---",a)
#work2 读取全局变量的值,如果能读到说全局变量能共享,否则不能共享
def work2():
print("---work2---", a)
#定义两个进程
if __name__ == '__main__':
work1_process=multiprocessing.Process(target=work1)
work2_process = multiprocessing.Process(target=work2)
work1_process.start()
work2_process.start()
time.sleep(3)
print("---main---", a)
结果:
从上面的主进程和子进程返回的值我们可以看到进程间的全局变量不共享,每个子进程分别获取变量,互补影响。
守护主进程
通过daemon设置子进程来守护主进程,在进程中我们知道主进程创建了子进程,当子进程执行的时候,主进程一定在执行或等待,待子进程执行完,主进程方可结束,当主进程一旦结束,子进程就随子结束了。
守护主进程(daemon=True):
#encoding:utf-8
import multiprocessing
import time
import os
#定义模块
def work():
for i in range(10):
print("子进程正在运行%d"%(i+1))
time.sleep(0.5)
if __name__ == '__main__':
# 导入模块
# 创建进程
process_obj = multiprocessing.Process(target=work)
#设置进程
process_obj.daemon=True
# 启动进程
process_obj.start()
time.sleep(2)
print("主进程要退出 ")
exit() #退出
结果:
从上面看我们主进程一旦决定退出,那么子进程也得结束,这就是守护,子进程和主进程还存在一种关系,
#encoding:utf-8
import multiprocessing
import time
import os
#定义模块
def work():
for i in range(10):
print("子进程正在运行%d"%(i+1))
time.sleep(0.5)
if __name__ == '__main__':
# 导入模块
# 创建进程
process_obj = multiprocessing.Process(target=work)
#设置进程
process_obj.daemon=True
# 启动进程
process_obj.start()
time.sleep(2)
#终止子进程
process_obj.terminate()
print("主进程要退出 ")
exit() #退出
结果:
这种关系就是通过terminate()提前终止子进程,这么一来子进程提前结束了,主进程也就可以结束了,这两种方式均可子进程与主进程之间的约定。