Python多进程

  进程,顾名思义就是进行中的程序,一堆代码文件不是一个程序,只有当代码文件被加载到了内存运行起来之后才是一个进程。同一款软件运行两次,代表着两个进程。

  为了提高程序的运行效率,出现了并行和并发的概念,并行利用了多核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('主进程代码执行完毕')

  在上面的代码中,主进程执行完毕之后,子进程也会结束,所以打印结果如下:

子进程开始执行
主进程代码执行完毕