Python的进程及进程池详解
作者:程序员-夏天 发布时间:2021-05-18 08:51:46
进程
进程是操作系统分配资源的基本单元,是程序隔离的边界。
进程和程序
程序只是一组指令的集合,它本身没有任何运行的含义,它是静态的。
进程程序的执行实例,是动态的,有自己的生命周期,有创建有撤销,存在是暂时的。
进程和程序不是一一对应的,一个程序可以对应多个进程,一个进程也可以执行一个或者多个程序。
我们可以这样理解:编写完的代码,没有运行时称为程序,正在运行的代码,会启动一个(或多个)进程。
进程的状态
在我们的操作系统⼯作时,任务数往往⼤于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, )))
执行,进程池中的进程会等待上⼀个进程执行完任务后才能执⾏下⼀个进程。
来源:https://blog.csdn.net/weixin_50097774/article/details/121428457
猜你喜欢
- 背景在写代码过程中,如果有频繁重复性的编码操作,或者可以Reuse的各类代码,可以通过Python写一个脚本,自动生成这类代码,就不用每次手
- 目录1. 简介2. 示例代码13. 示例代码24. 启动异常1. 简介Gunicorn(Green Unicorn)是给Unix用的WSGI
- 如下所示:<span style="font-size:18px;"># -*- coding:utf-8
- 在这篇文章中,我们将讨论mask R-CNN背后的一些理论,以及如何在PyTorch中使用预训练的mask R-CNN模型。1.语义分割、目
- Gmail 作为一个经典的 Web 2.0 应用,在带来革命性的邮件管理体验的同时,以其完整、快速的 AJAX 操作方式,深受用户的推崇和技
- 尽管XML还处在开发阶段,其标准正在由W3C组织制定,但是已经有许多公司表示全力支持XML,并开发了不少XML工具。Adobe公司的Fram
- 阅读上一篇:打造设计你自己的字体 Ⅱ永远都在寻觅字体设计的灵感。夏天过后,我买了一套便宜的书法钢笔,说服自己,它会让我的鸡爬字产生脱胎换骨的
- 其实,这是一个非常容易解决掉的问题。在我看来,似曾相识,呵呵,最近学JavaScript可是学会了使用var声明变量。其实,在PHP中根本不
- 本文实例为大家分享了python使用正则筛选信用卡的具体代码,供大家参考,具体内容如下本文来源于两个简单的题目:1.判断一对单词是否是&qu
- 你的SQL Server最近是否运行不正常?不,我指的不是我们肯定会遇到的通常的数据库和操作系统问题。我的意思是,你是否经历过服务器的反应迟
- 现在电子商务网站的设计,正面临着一系列的挑战,其中最主要的挑战是:我们尝试建立一种用户体验,来提高用户在线购物的可能性。为了对抗网上激烈的竞
- format函数实现字符串格式化的功能基本语法为:通过 : 和 {} 来控制字符串的操作一、对字符串进行操作1. 不设置指定位置,按默认顺序
- 从容器、可迭代对象谈起所有的容器都是可迭代的(iterable),迭代器提供了一个next方法。iter()返回一个迭代器,通过next()
- 本文实例讲述了python模拟鼠标拖动操作的方法。分享给大家供大家参考。具体如下:pdf中的书签只有页码,准备把现有书签拖到一个目录中,然后
- 一、将PHP数组转换为JSON格式在PHP中,我们可以直接使用数组来存储数据。但是在JS中,数组通常以JSON(JavaScript Obj
- 这份代码不是那种时间没有改变也输出innerHTML的高消耗代码。innerHTML和style的改变是非常消耗游览器性能的,如果你将来希望
- 递归是以相似的方式重复项目的过程。同样适用于编程语言中,如果一个程序可以让你调用同一个函数被调用的函数,递归调用函数内使用如下。func r
- 在MySQL中,如何实现Top N及M至N段的记录查询?我们可以利用MySQL中SELECT支持的一个子句——LIMIT——来完成这项功能。
- 如何读取PDF文档(或TXT)字符串在Python内部的表示是Unicode编码,首先我们来认识Python中encode()和decode
- 一、介绍Django特点:具有完整的封装,开发者可以高效率的开发项目,Django将大部分的功能进行了封装,开发者只需要调用即可,如此,大大