进程,顾名思义就是进行中的程序,一堆代码文件不是一个程序,只有当代码文件被加载到了内存运行起来之后才是一个进程。同一款软件运行两次,代表着两个进程。
为了提高程序的运行效率,出现了并行和并发的概念,并行利用了多核CPU的优势,把任务分配到不同的CPU上独立运行。而并发更像是一种伪并行,在单核CPU上,通过在不同进程间切换,达到多个进程同时运行的目的。
在计算机中,创建进程输入操作系统的工作范畴,当我们在Python编辑器中写下创建新进程的代码并执行的时候,Python解释器会将创建进程的请求交给操作系统,由操作系开辟内存空间完成创建。
在Python编程语言中,创建进程的方式主要有两种,第一种通过传递函数给Process类来创建进程。
from multiprocessing import Process def task(name): print('这是子进程') if __name__ == '__main__': p = Process(target=task, args=('process1', )) p.start() print('这是主进程的代码')
在这种方式中,先将需要并发执行的代码写到一个函数中,然后再main里面创建Process实例(注意:创建进程要放到if __name__ == '__main__':中,因为在windows平台下,创建子进程时相当于导入模块,会先把代码执行一遍),然后把需要并发的函数传递而target参数,把函数接收的参数以元组的形式传递给args参数,或者以字典的方式传递给kwargs参数。
创建进程的第二种方式是以继承Process类的方式创建新类,然后重写父类的run方法。
from multiprocessing import Process class MyProcess(Process): def __init__(self, name): super().__init__() seld.name = name def run(self): print('这是子进程%s' % self.name) if __name__ == '__main__': p = MyProcess('线程1') p.start() print('这是主进程代码')
在这种方式中,需要并发执行的代码是方法MyProcess类的run方法里面的,如果需要对其传递函数,则需要重写__init__方法,并且在该方法内调用父类的__init__方法 。
对于第一种和第二种方式,我们都是都得一个进程对象,所以相应的,也可以调用该对象的方来查看和修改进程的状态。
进程对象主要的方法如下:
p.start() # 启动进程,这个操作是提交给操作系统的,所以说不是一p.start()就立马执行,而是由操作系统进行调度 p.terminate() # 强制终止进程,并且不会进行任何操作,也就是说,如果该进程进行了枷锁操作,当该进程成为僵尸进程的时候,并不会释放锁 p.is_alive() # 查看进程的存活状态 p.join([timeout]) # 让主进程代码等待p的结束,也就是说,当p没有结束的时候,p.join()后面的代码不会被执行,timeout可以设置超时时间
上面提到了僵尸进程和孤儿进程,僵尸进程就是当主进程创建了子进程,子进程执行完毕或者被terminate之后,系统只会回收子进程的内存空间,不会完全释放子进程,该子进程就成了僵尸进程。同理,孤儿进程指的是主进程被释放,又主进程创建出来的子进程还没有结束,这些子进程就成了孤儿进程。孤儿进程与僵尸进程的区别在于,僵尸进程对于程序是有害的,会占用系统资源,而孤儿进程是无害的。
如果我们想要一个子进程在主进程的代码执行完毕之后也自动结束,可以使用到守护进程。
from multiprocessing import Process import time def task(): print('子进程开始执行') time.sleep(3) print('子进程运行结束') if __name__ == '__main__': p = Process(target=task) p.daemon = True p.start() time.sleep(2) print('主进程代码执行完毕')
在上面的代码中,主进程执行完毕之后,子进程也会结束,所以打印结果如下:
子进程开始执行
主进程代码执行完毕