Python的进程及进程池详解

 更新时间:2021年11月25日 15:04:29   作者:程序员-夏天  
这篇文章主要为大家介绍了Python的进程及进程池,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

进程

进程是操作系统分配资源的基本单元,是程序隔离的边界。

进程和程序

程序只是一组指令的集合,它本身没有任何运行的含义,它是静态的。

进程程序的执行实例,是动态的,有自己的生命周期,有创建有撤销,存在是暂时的。

进程和程序不是一一对应的,一个程序可以对应多个进程,一个进程也可以执行一个或者多个程序。

我们可以这样理解:编写完的代码,没有运行时称为程序,正在运行的代码,会启动一个(或多个)进程。

进程的状态

在我们的操作系统⼯作时,任务数往往⼤于cpu核心数,即⼀定有⼀些任务正在执⾏,⽽另外⼀些任务在等待cpu,因此导致了进程有不同的状态。

  • 就绪状态:已满⾜运⾏条件,等待cpu执⾏
  • 执⾏状态:cpu正在执⾏
  • 等待状态:等待某些条件满⾜,比如⼀个程序sleep了,此时就处于等待状态

Python中的进程

在Python中,进程是通过multiprocessing多进程模块来创建的,multiprocessing模块提供了⼀个Process类来创建进程对象。

创建⼦进程

Process语法结构:

Process(group, target, name, args, kwargs)

  • group:指定进程组,⼤多数情况下⽤不到
  • target:表示调用对象,即子进程要执行的任务
  • name:子进程的名称,可以不设定
  • args:给target指定的函数传递的参数,以元组的⽅式传递
  • kwargs:给target指定的函数传递命名参数

Process常用方法

  • p.start() 启动进程,并调用该子进程中的p.run()方法
  • p.join(timeout):主进程等待⼦进程执⾏结束再结束,timeout是可选的超时时间
  • is_alive():判断进程⼦进程是否还存活
  • p.run() 进程启动时运行的方法,正是它去调用target指定的函数
  • p.terminate() ⽴即终⽌⼦进程

Process创建的实例对象的常⽤属性

name:当前进程的别名,默认为Process-N,N为从1开始递增的整数

pid:当前进程的pid(进程号)

import multiprocessing
import os
import time
def work(name):
    print("子进程work正在运行......")
    time.sleep(0.5)
    print(name)
    # 获取进程的名称
    print("子进程name", multiprocessing.current_process())
    # 获取进程的pid
    print("子进程pid", multiprocessing.current_process().pid, os.getpid())
    # 获取父进程的pid
    print("父进程pid", os.getppid())
    print("子进程运行结束......")
if __name__ == '__main__':
    print("主进程启动")
    # 获取进程的名称
    print("主进程name", multiprocessing.current_process())
    # 获取进程的pid
    print("主进程pid", multiprocessing.current_process().pid, os.getpid())
    # 创建进程
    p = multiprocessing.Process(group=None, target=work, args=("tigeriaf", ))
    # 启动进程
    p.start()
    print("主进程结束")

通过上述代码我们发现,multiprocessing.Process帮我们创建一个子进程,并且成功运行,但是我们发现,在子进程还没执行完的时候主进程就已经死了,那么这个子进程在主进程结束后就是一个孤儿进程,那么我们可以让主进程等待子进程结束后再结束吗?答案是可以的。 那就是通过p.join(),join()的作用是让主进程等子进程执行完再退出。

import multiprocessing
import os
import time
def work(name):
    print("子进程work正在运行......")
    time.sleep(0.5)
    print(name)
    # 获取进程的名称
    print("子进程name", multiprocessing.current_process())
    # 获取进程的pid
    print("子进程pid", multiprocessing.current_process().pid, os.getpid())
    # 获取父进程的pid
    print("父进程pid", os.getppid())
    print("子进程运行结束......")
if __name__ == '__main__':
    print("主进程启动")
    # 获取进程的名称
    print("主进程name", multiprocessing.current_process())
    # 获取进程的pid
    print("主进程pid", multiprocessing.current_process().pid, os.getpid())
    # 创建进程
    p = multiprocessing.Process(group=None, target=work, args=("tigeriaf", ))
    # 启动进程
    p.start()
    p.join()
    print("主进程结束")

运行结果:

可以看出,主进程是在子进程结束后才结束的。

全局变量问题

全局变量在多个进程中不共享,进程之间的数据是独立的,默认情况下互不影响。

import multiprocessing
# 定义全局变量
num = 99
def work1():
    print("work1正在运行......")
    global num   # 在函数内部声明使⽤全局变量num
    num = num + 1  # 对num值进⾏+1
    print("work1 num = {}".format(num))
def work2():
    print("work2正在运行......")
    print("work2 num = {}".format(num))
if __name__ == '__main__':
    # 创建进程p1
    p1 = multiprocessing.Process(group=None, target=work1)
    # 启动进程p1
    p1.start()
    # 创建进程p2
    p2 = multiprocessing.Process(group=None, target=work2)
    # 启动进程p2
    p2.start()

运行结果:

从运⾏结果可以看出,work1()函数对全局变量num的修改,在work2中并没有获取到,⽽还是原来的99,所以,进程之间是不够共享变量的。

守护进程

上面说到,可以使用p.join()让主进程等待子进程结束后再结束,那么可不可以让子进程在主进程结束的时候就结束呢?答案是肯定的。 我们可以使用p.daemon = True或者p2.terminate()进行设置:

import multiprocessing
import time
def work1():
    print("work1正在运行......")
    time.sleep(4)
    print("work1运行完毕")
def work2():
    print("work2正在运行......")
    time.sleep(10)
    print("work2运行完毕")
if __name__ == '__main__':
    # 创建进程p1
    p1 = multiprocessing.Process(group=None, target=work1)
    # 启动进程p1
    p1.start()
    # 创建进程p2
    p2 = multiprocessing.Process(group=None, target=work2)
    # 设置p2守护主进程
    # 第⼀种⽅式
    # p2.daemon = True  在start()之前设置,不然会抛异常
    # 启动进程p2
    p2.start()
    time.sleep(2)
    print("主进程运行完毕!")
    # 第⼆种⽅式 
    p2.terminate()

执行结果如下:

由于p2设置了守护主进程,所以主进程运行完毕后,p2子进程也随之结束,work2任务停止,而work1继续运行至结束。

进程池

当需要创建的⼦进程数量不多时, 可以直接利⽤multiprocessing.Process动态生成多个进程, 但如果要创建很多进程时,⼿动创建的话⼯作量会非常大,此时就可以⽤到multiprocessing模块提供的Pool去创建一个进程池。

multiprocessing.Pool常⽤函数:

  • apply_async(func, args, kwds):使⽤⾮阻塞⽅式调⽤func(任务并⾏执⾏),args为传递给func的参数列表,kwds为传递给func的关键字参数列表
  • apply(func, args, kwds):使⽤阻塞⽅式调⽤func,必须等待上⼀个进程执行完任务后才能执⾏下⼀个进程,了解即可,几乎不用
  • close():关闭Pool,使其不再接受新的任务
  • terminate():不管任务是否完成,⽴即终⽌
  • join():主进程阻塞,等待⼦进程的退出,必须在close或terminate之后使⽤

初始化Pool时,可以指定⼀个最⼤进程数,当有新的任务提交到Pool中时,如果进程池还没有满,那么就会创建⼀个新的进程⽤来执⾏该任务,但如果进程池已满(池中的进程数已经达到指定的最⼤值),那么该任务就会等待,直到池中有进程结束才会创建新的进程来执⾏。

from multiprocessing import Pool
import time
def work(i):
    print("work'{}'执行中......".format(i), multiprocessing.current_process().name, multiprocessing.current_process().pid)
    time.sleep(2)
    print("work'{}'执行完毕......".format(i))
if __name__ == '__main__':
    # 创建进程池
    # Pool(3) 表示创建容量为3个进程的进程池
    pool = Pool(3)
    for i in range(10):
        # 利⽤进程池同步执⾏work任务,进程池中的进程会等待上⼀个进程执行完任务后才能执⾏下⼀个进程
        # pool.apply(work, (i, ))
        # 使⽤异步⽅式执⾏work任务
        pool.apply_async(work, (i, ))
    # 进程池关闭之后不再接受新的请求
    pool.close()
    # 等待po中所有子进程结束,必须放在close()后面, 如果使⽤异步⽅式执⾏work任务,主线程不再等待⼦线程执⾏完毕再退出!
    pool.join()

执行结果为:

从结果我们可以看出,只有3个子进程在执行任务,此处我们使用的是异步⽅式(pool.apply_async(work, (i, )))执⾏work任务,如果是以同步方式(pool.apply(work, (i, )))执行,进程池中的进程会等待上⼀个进程执行完任务后才能执⾏下⼀个进程。

总结

本篇只介绍了什么是进程、进程与程序的关系、进程的创建与使用、创建进程池等,并没有介绍进程同步及进程通信等,下篇文章将会介绍。

相关文章

  • Python 中的Sympy详细使用

    Python 中的Sympy详细使用

    这篇文章主要介绍了Python 中的Sympy详细使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • Python实现连接MySql数据库及增删改查操作详解

    Python实现连接MySql数据库及增删改查操作详解

    这篇文章主要介绍了Python实现连接MySql数据库及增删改查操作,结合实例形式详细分析了Python安装PyMySQL模块及使用PyMySQL模块进行mysql数据库的连接、增删改查等相关操作技巧,需要的朋友可以参考下
    2019-04-04
  • Python 专题四 文件基础知识

    Python 专题四 文件基础知识

    本文主要讲述了Python文件基础知识,包括文件的打开、读写、关闭操作、使用循环读写文件及迭代器的知识。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • pandas通过loc生成新的列方法

    pandas通过loc生成新的列方法

    今天小编就为大家分享一篇pandas通过loc生成新的列方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • python调用opencv实现猫脸检测功能

    python调用opencv实现猫脸检测功能

    这篇文章主要介绍了python调用opencv实现猫脸检测功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • Python Pandas模块实现数据的统计分析的方法

    Python Pandas模块实现数据的统计分析的方法

    在上一篇讲了几个常用的“Pandas”函数之后,今天小编就为大家介绍一下在数据统计分析当中经常用到的“Pandas”函数方法,希望能对大家有所收获,需要的朋友可以参考下
    2021-06-06
  • 用python实现的线程池实例代码

    用python实现的线程池实例代码

    这篇文章主要介绍了用python实现的线程池实例代码,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • 实例讲解Python中整数的最大值输出

    实例讲解Python中整数的最大值输出

    在本篇文章里小编给大家分享了关于Python中整数的最大值输出的实例内容,以及相关知识点,需要的朋友们学习下。
    2019-03-03
  • Django之提交表单与前后端交互的方法

    Django之提交表单与前后端交互的方法

    今天小编就为大家分享一篇Django之提交表单与前后端交互的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Python Pandas 如何shuffle(打乱)数据

    Python Pandas 如何shuffle(打乱)数据

    这篇文章主要介绍了Python Pandas 如何shuffle(打乱)数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07

最新评论