irpas技术客

〖Python语法进阶篇③〗- 进程的创建与常用方法_全栈哈士奇

大大的周 7790

万叶集🎉 隐约雷鸣,阴霾天空。 🎉🎉 但盼风雨来,能留你在此。 🎉

前言: ? 作者简介:渴望力量的哈士奇 ?,大家可以叫我 🐶哈士奇🐶 ,一位致力于 TFS 赋能的博主 ? 🏆 CSDN博客专家认证、新星计划第三季全栈赛道 top_1 、华为云享专家、阿里云专家博主 🏆 📫 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 💬 人生格言:优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬 🔥 如果感觉博主的文章还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主哦


专栏系列(点击解锁)学习路线指引知识定位 🔥Python全栈白皮书🔥 零基础入门篇 以浅显易懂的方式轻松入门,让你彻底爱上Python的魅力。 语法进阶篇 主要围绕多线程编程、正则表达式学习、含贴近实战的项目练习 。 自动化办公篇 实现日常办公软件的自动化操作,节省时间、提高办公效率。 自动化测试实战篇 从实战的角度出发,先人一步,快速转型测试开发工程师。 数据库开发实战篇 更新中 爬虫入门与实战 更新中 数据分析篇 更新中 前端入门+flask 全栈篇 更新中 django+vue全栈篇 更新中 拓展-人工智能入门 更新中 网络安全之路 踩坑篇 记录学习及演练过程中遇到的坑,便于后来居上者 网安知识扫盲篇 三天打鱼,不深入了解原理,只会让你成为脚本小子。 vulhub靶场漏洞复现 让漏洞复现变得简单,让安全研究者更加专注于漏洞原理本身。 shell编程篇 不涉及linux基础,最终案例会偏向于安全加固方向。 [待完结] WEB漏洞攻防篇 2021年9月3日停止更新,转战先知社区等安全社区及小密圈 渗透工具使用集锦 2021年9月3日停止更新,转战先知社区等安全社区及小密圈 点点点工程师 测试神器 - Charles 软件测试数据包抓包分析神器 测试神器 - Fiddler 一文学会 fiddle ,学不会倒立吃翔,稀得! 测试神器 - Jmeter 不仅是性能测试神器,更可用于搭建轻量级接口自动化测试框架。 RobotFrameWork Python实现的自动化测试利器,该篇章仅介绍UI自动化部分。 Java实现UI自动化 文档写于2016年,Java实现的UI自动化,仍有借鉴意义。 MonkeyRunner 该工具目前的应用场景已不多,文档已删,为了排版好看才留着。


文章目录 进程的创建模块 - multiprocessing创建进程函数 - Process 进程的常用方法start 函数join 函数kill 函数 与 is_alive 函数 进程的相关问题

该章节我们来学习一下在 Python 中去创建并使用多进程的方法,通过学习该章节,我们将可以通过创建多个进程来帮助我们提高脚本执行的效率。可以认为缩短脚本执行的时间,就是提高执行我们脚本的效率。接下来让我们都看一下今天的章节知识点都有哪些?

进程的创建模块 - multiprocessing 创建进程函数 - Process 函数名介绍参数返回值Process创建一个进程target, args进程对象

Process功能介绍:实例化一个对象;它需要传入两个参数 target 与 args:target 是一个函数,args 是对应一个函数的参数(args参数是一个元组)。其实我们可以这样去理解,在一个脚本中创建子进程,目的是为了让它执行我们脚本中的某个函数。换句话讲,我们将脚本中的某一个函数单独的启用一个进程去执行。

我们说过进程之间互不干扰,可以同时执行。所以我们可以认为主进程中的程序和子进程的函数是相互不干扰的,听起来可能很难理解,一会儿下文我们进行一个案例的小练习,一遍帮助大家去更好的理解其中的含义。

进程的常用方法 函数名介绍参数返回值start执行进程无无join阻塞进程无无kill杀死进程无无is_alive判断进程是否存活无bool

start 函数:通过调用它,可以直接启动我们创建的进程。它会马上执行我们进程中传入的函数,start 函数没有任何参数,也没有返回值。

join 函数:我们说过,主进程和子进程的程序会同时运行,互不影响。这样就会有一个问题,有可能是 子进程 先执行完它的业务,也有可能是 主进程 先执行完它的业务逻辑。如果有的时候我们必须要先执行完 子进程的业务 再执行 主进程的业务 。则通过调用 join 函数,在这一函数下面执行的主进程业务要等待子进程完成之后才会继续执行。我们将 join 这样的函数叫做 等待/阻塞函数。join 函数没有任何参数,也没有返回值。

kill 函数:如果我们在执行子进程的过程中发现不需要这个子进程继续运行了,就可以使用 kill 函数杀死当前的这个子进程,杀死的这个子进程不会在执行子进程中函数的业务逻辑。kill 函数没有任何参数,也没有返回值。

is_alive 函数:通过调用这个函数可以判断当前的进程是否是存活状态,它返回一个 bool 值。True 表示当前进程还在,程序还在继续执行;如果是 False 则代表当前进程已经结束了

start 函数

演示案例:

我们先定义两个简单的函数,每个函数定义两个简单的 for 循环。

每执行一次循环,休眠一秒的时间。

在两次循环的开始定义一个实例化时间对象,用以计算两次循环的时间间隔。

同时,获取脚本执行的进程号; 看看是一个怎样的结果。

# coding:utf-8 import time import os def work_for_first(): for i in range(5): print('\'work_for_first\' 函数的循环值:%s', '进程号为:%s' % i, os.getpid()) # os.getpid() 为获取进程号函数 time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函数的循环值:%s', '进程号为:%s' % i, os.getpid()) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 获取执行 循环 之前的时间戳 work_for_first() work_for_second() end_time = time.time() - start_time # 获取执行 循环 结束的时间戳 print('耗时时间为:{}, 进程号为:{}'.format(end_time, os.getpid())) # 获取耗时与进程号

执行结果如下图:



OKK!接下来进入我们今天要学习的主题。

将 work_for_first() 函数创建一个新的子进程去执行。

# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 获取执行 循环 之前的时间戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因为我们传入的函数没有参数所以 args 可以不写 work_for_first_process.start() work_for_second() end_time = time.time() - start_time # 获取执行 循环 结束的时间戳 print('耗时时间为:{}, 进程号为:{}'.format(end_time, os.getpid())) # 获取耗时与进程号

执行结果如下图:



因为我们针对 work_for_first() 函数创建一个新的子进程去执行,所以我们的耗时变为了 5秒。那么如果我们将 work_for_second() 函数也创建一个新的子进程去执行,耗时又会是多少呢?我们接着往下看。

# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 获取执行 循环 之前的时间戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因为我们传入的函数没有参数所以 args 可以不写 work_for_first_process.start() work_for_second_process = multiprocessing.Process(target=work_for_second) work_for_second_process.start() end_time = time.time() - start_time # 获取执行 循环 结束的时间戳 print('耗时时间为:{}, 进程号为:{}'.format(end_time, os.getpid())) # 获取耗时与进程号

执行结果如下图:


PS:从脚本中执行入口的 main 函数可以看出 work_for_first() 函数 与 work_for_second() 函数 分别都由各自的子进程来执行,主进程实际执行的 只有 23行、29行、30行代码,所以从耗时来看,主进程实际上只执行了 0.026 秒。

这里再思考一个问题,如果是每一个子进程都单独的通过 .start 去启动,那么在子进程很多的情况下,启动的确实会有一些慢了。这个时候我们就可以通过 for 循环的方式去启动子进程。方式如下:

for sun_process in (work_for_first_process, work_for_second_process): sun_process.start()
join 函数

同样的也会存在着这样一种情况,我们希望子进程运行结束之后再去执行我们的主进程,这时候我们就会使用到 join 函数 。

这里我们就利用上文的 进程 for循环同时启动两个子进程,然后我们再在下一个 for循环 执行 join 函数,我们看看会发生什么。

# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 获取执行 循环 之前的时间戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因为我们传入的函数没有参数所以 args 可以不写 # work_for_first_process.start() work_for_second_process = multiprocessing.Process(target=work_for_second) # work_for_second_process.start() for sun_process in (work_for_first_process, work_for_second_process): sun_process.start() for sun_process in (work_for_first_process, work_for_second_process): sun_process.join() end_time = time.time() - start_time # 获取执行 循环 结束的时间戳 print('耗时时间为:{}, 进程号为:{}'.format(end_time, os.getpid())) # 获取耗时与进程号

执行结果如下图:



kill 函数 与 is_alive 函数

接下来我们再尝试一个场景,利用 for 循环,我们同时启动 work_for_first() 函数 与 work_for_second() 函数 的子进程。然后我们再在另一个 for 循环中,将 work_for_second() 函数 的子进程 kill 掉,然后判断两个子进程的存活状态。

示例脚本如下:

# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函数的循环值:{},进程号为:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 获取执行 循环 之前的时间戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因为我们传入的函数没有参数所以 args 可以不写 # work_for_first_process.start() work_for_second_process = multiprocessing.Process(target=work_for_second) # work_for_second_process.start() for sun_process in (work_for_first_process, work_for_second_process): sun_process.start() time.sleep(1) # 休眠一秒是为了 work_for_second_process 子进程 至少能够运行一次 for sun_process in (work_for_first_process, work_for_second_process): work_for_second_process.kill() if work_for_first_process.is_alive(): print('\'work_for_first_process\' 子进程当前存活状态为:True') elif not work_for_second_process.is_alive(): print('\'work_for_second_process\' 子进程当前存活状态为:False') sun_process.join() end_time = time.time() - start_time # 获取执行 循环 结束的时间戳 print('耗时时间为:{}, 进程号为:{}'.format(end_time, os.getpid())) # 获取耗时与进程号

运行结果如下:



进程的相关问题

通过学习多进程的创建、启动,我们可以充分的体会到进程给我们带来的好处。它可以使我们的脚本程序执行时间进行缩短,从而提高工作效率。

然而多进程也有一些问题:

通过进程模块执行的函数无法获取返回值,即便这个函数拥有 return 关键字也无法获取到,这也是我们进程的弊端。

多个进程同时修改文件可能会出现错误。

进程数量太多可能会造成资源不足、甚至死机等情况。

关于进程的这些问题,其实也并不是不能解决。在后续更新的 进程间的通信 、进程池与进程锁 的章节我们再进行详细的介绍。

累了,拜了个拜...


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #Python语法进阶篇③ #进程的创建与常用方法 #该章节我们来学习一下在 #Python