跨平台的进程创建模块
1.方法一: 使用 Process 类创建子进程
支持跨平台:windows / linux
multiprocessing 提供了一个 Process 类来代表一个进程对象
from multiprocessing import Process
import os
def download(fileName, type, **kwargs):
print('开启进程下载,进程号为:%s' % os.getpid())
if kwargs['device'] == 'iphoneX':
path = "http://www.baidu.com/iphoneX"
# print("下载路径为:%s/%s.%s" % (path, fileName, type))
print("下载路径为: %s/%s.%s" % (path, fileName, type))
if __name__ == '__main__':
# 1.创建和启动
# 创建格式: p = Process(target=函数名) 为某个功能函数创建多进程
# 注意函数名后面不可以加括号
p = Process(target=download, name="下载进程", args=("logo", "png"), kwargs={"device":"iphoneX"})
# 2.对子进程的操作:一定要放在p.start()前面,否则可能会在执行子进程的操作时,子进程就有可能已经被释放掉了。
# 打印别名
print(p.name)
# 启动子进程,对象不start的话子进程的函数就不会执行。
p.start()
print("下载完成")
'''
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
参数分析
group: 分组(基本不用)
target: 表示这个进程实例所调用的对象
name: 给进程起一个别名
args: 参数,表示非关键字收集参数,使用元组收集
kwargs: 表示关键字收集参数,使用字典收集
'''
上述代码返回值:
下载进程
下载完成
开启进程下载,进程号为:17344
下载路径为: http://www.baidu.com/iphoneX/logo.png
1.1 代码拓展
上述代码还有个问题:
因子进程的文件还没有下载完成,就已经print("下载完成")。
所以需要主进程等待子进程执行完成之后,主进程才接着往下执行
1.1.1 阻塞主进程和子进程的生命状态
使用阻塞解决上述问题 join()
使用 join() 阻塞主进程执行
应用场景:更新系统时,会先下载安装包,会使用多进程阻塞安装的主进程,等所有安装包都下载完成后,才开始安装软件
拓展:
-
以下是 join() 的源码
def join(self, timeout=None): pass
-
timeout 的参数:主进程设置阻塞时间,不管子进程完成与否,阻塞时间到了之后,主进程都继续执行。
-
p.join(5) 设置阻塞5秒,
-
注意点:设置阻塞5 秒,如果子进程在5秒以内执行完毕了,主进程会继续执行剩下的内容,而不会死等到5秒才执行剩下的内容
进程的生命状态 is_alive()
- 格式:p.is_alive()
- 返回值:
- True: 子进程活着
- False: 子进程结束
1.1.2 终止子进程
-
格式:p.terminate()
-
作用:不管进程是否完成,立即终止
-
通常 join() 、is_alive() 和 **terminate() **这三个方法连用,代码如下
- 代码示例
p.join(4) if p.is_alive() == Ture: p.terminate()
2. 方法二:定义类创建子进程(推荐使用这种方法)
- 可以使用定义类的方式,并继承Process类,来创建子进程
- 实例化这个类,就相当于实例化了一个进程对象
from multiprocessing import Process
import os
import time
# 定义一个类,继承 Process 类
class ManualProcess(Process):
def __init__(self,interval):
# 继承 Process 类的初始化方法,提供传参
Process.__init__(self)
self.interval = interval
# 重写 Process 类中的 run() 方法,run()方法为 Process类的中执行子进程中函数的方法
# 这块是核心
def run(self):
t_start = time.time()
print('子进程(%s)开始执行,父进程为(%s)' % (os.getpid(), os.getppid()))
time.sleep(self.interval)
t_stop = time.time()
print('(%s)进程执行结束,耗时%.2f秒' % (os.getpid(), (t_stop - t_start)))
if __name__ == '__main__':
t_start = time.time()
print('当前程序的进程号为:%s ' % os.getpid())
p = ManualProcess(interval=2)
# 对于一个不包含target属性的Process类(实例化时,没有给 target 传参),如果执行了start()方法
# 表示子进程就会运行类中的run()方法
p.start()
p.join()
t_stop = time.time()
print('(%s)进程执行结束,耗时%.2f秒' % (os.getpid(),(t_stop - t_start)))
代码返回值如下:
当前程序的进程号为:14040
子进程(4240)开始执行,父进程为(14040)
(4240)进程执行结束,耗时2.01秒
(14040)进程执行结束,耗时2.55秒
下图为继承Process类创建子进程的方法注意要点
- 图中的 (1)(2)(3)(4)红色区域表示是必须要写的部分,类似框架的意思
- 蓝色区域是自定义功能的区域,以便后期做代码扩展或重新写功能
3. 代码练习
-
需求:
- 键盘输入一个整数,分别开启两个进程来计算这个输的累加和与阶乘
- 第一个进程使用系统提供给我们的类
- 第二个进程需要自己定义
from multiprocessing import Process import time import os # 定义阶乘进程类 class FactorialClass(Process): def __init__(self,interval): # 继承Process类的初始化方法 Process.__init__(self) self.interval = interval # 定义阶乘方法 def run(self): t_start = time.time() res = 1 for i in range(1, self.interval+1): res *= i t_stop = time.time() print('阶乘子进程(%s)执行完毕,累计耗时 %.7f 秒' % (res, t_stop - t_start)) print('%d的阶乘为%d' % (self.interval, res)) return res # 累加功能 def accumulate(interval): t_start = time.time() res = 0 for i in range(1,interval+1): res += i t_stop = time.time() print('累加子进程(%s)执行完毕,累计耗时 %.7f 秒' % (res, t_stop-t_start)) print('%d的累加和为%d' % (interval, res)) return res # 程序入口 def main(): try: interval = int(input("请输入一个整数:")) #定义程序开始时间 t_start = time.time() # 实例化Process类 p1 = Process(target=accumulate,args=(interval,)) # 实例化自定义类 p2 = FactorialClass(interval) # 开启 p1和p2 进程 p1.start() p2.start() # 设置阻塞 p1.join() p2.join() # 定义程序结束时间 t_stop = time.time() print('主进程(%s)执行完毕,累计耗时 %.7f 秒' % (os.getpid(), t_stop-t_start)) except Exception as f: print("输入有误,结束") if __name__ == '__main__': main()
网友评论