通过实例解析python创建进程常用方法


Posted in Python onJune 19, 2020

 运行程序时,单线程或单进程往往是比较慢的,为加快程序运行速度,我们可以使用多进程,可以理解为多任务同时运行,小编的电脑是四核,所以可以设置四个进程。

下面,我们来了解下多进程的使用:

1、使用multiprocessing模块创建进程

multiprocessing模块提供了一个Process类来代表进程对象,语法如下:

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

其中,group:参数未使用,值始终是None

target:表示当前进程启动时执行的可调用对象

name:为当前进程实例的别名

args:表示传递给target函数的参数元组

kwargs:表示传递给target函数的参数字典

使用多进程的一个简单例子:

from multiprocessing import Process   # 导入模块

# 执行子进程代码
def test(interval):
  print('我是子进程')
# 执行主程序
def main():
  print('主进程开始')
  # 实例化Procss进程类
  p = Process(target=test,args=(1,))
  # 启动子进程
  p.start()
  print('主进程结束')

if __name__ == '__main__':
  main()

结果:

主进程开始
主进程结束
我是子进程

Process的实例p常用的方法除start()外,还有如下常用方法:

is_alive():判断进程实例是否还在执行

join([timeout]):是否等待进程实例执行结束,或等待多少秒

start():启动进程实例(创建子进程)

run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法

terminate():不管任务是否完成,立即终止

Process类还有如下常用属性:

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

pid:当前进程实例的PID值

下面是Process类方法和属性的使用,创建两个子进程,分别使用os模块和time模块输出父进程和子进程的id以及子进程的时间,并调用Process类的name和pid属性:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#两个子进程将会调用的两个方法
def child_1(interval):
  print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))
  # 计时开始
  t_start = time.time()
  # 程序将会被挂起interval秒
  time.sleep(interval)
  # 计时结束
  t_end = time.time()
  print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))

def child_2(interval):
  print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))
  # 计时开始
  t_start = time.time()
  # 程序将会被挂起interval秒
  time.sleep(interval)
  # 计时结束
  t_end = time.time()
  print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))

if __name__ == '__main__':
  print("------父进程开始执行-------")
  # 输出当前程序的ID
  print("父进程PID:%s" % os.getpid())
  # 实例化进程p1
  p1=Process(target=child_1,args=(1,))
  # 实例化进程p2
  p2=Process(target=child_2,name="mrsoft",args=(2,))
  # 启动进程p1
  p1.start()
  # 启动进程p2
  p2.start()
  #同时父进程仍然往下执行,如果p2进程还在执行,将会返回True
  print("p1.is_alive=%s"%p1.is_alive())
  print("p2.is_alive=%s"%p2.is_alive())
  #输出p1和p2进程的别名和PID
  print("p1.name=%s"%p1.name)
  print("p1.pid=%s"%p1.pid)
  print("p2.name=%s"%p2.name)
  print("p2.pid=%s"%p2.pid)
  print("------等待子进程-------")
  # 等待p1进程结束
  p1.join()
  # 等待p2进程结束
  p2.join()
  print("------父进程执行结束-------")

结果:

------父进程开始执行-------
父进程PID:13808
p1.is_alive=True
p2.is_alive=True
p1.name=Process-1
p1.pid=13360
p2.name=mrsoft
p2.pid=21500
------等待子进程-------
子进程(13360)开始执行,父进程为(13808)
子进程(21500)开始执行,父进程为(13808)
子进程(13360)执行时间为'1.01'秒
子进程(21500)执行时间为'2.00'秒
------父进程执行结束-------

上述代码中,第一次实例化Process类时,会为name属性默认赋值为Process-1,第二次则默认为Process-2,但由于实例化进程p2时,设置了name属性为mrsoft,所以p2.name的值为mrsoft。

2、使用Process子类创建进程

对于一些简单的小任务,通常使用Process(target=test)方式实现多进程。但如果要处理复杂任务的进程,通常定义一个类,使其继承Process类,下面是通过使用Process子类创建多个进程。

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#继承Process类
class SubProcess(Process):
  # 由于Process类本身也有__init__初识化方法,这个子类相当于重写了父类的这个方法
  def __init__(self,interval,name=''):
    # 调用Process父类的初始化方法
    Process.__init__(self)
    # 接收参数interval
    self.interval = interval
    # 判断传递的参数name是否存在
    if name:
      # 如果传递参数name,则为子进程创建name属性,否则使用默认属性
      self.name = name    
  #重写了Process类的run()方法
  def run(self):
    print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
    t_start = time.time()
    time.sleep(self.interval)
    t_stop = time.time()
    print("子进程(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":
  print("------父进程开始执行-------")
  # 输出当前程序的ID
  print("父进程PID:%s" % os.getpid())         
  p1 = SubProcess(interval=1,name='mrsoft')
  p2 = SubProcess(interval=2)
  #对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,
  #所以这里会执行p1.run()
  # 启动进程p1
  p1.start()
  # 启动进程p2
  p2.start() 
  # 输出p1和p2进程的执行状态,如果真正进行,返回True,否则返回False
  print("p1.is_alive=%s"%p1.is_alive())
  print("p2.is_alive=%s"%p2.is_alive())
  #输出p1和p2进程的别名和PID
  print("p1.name=%s"%p1.name)
  print("p1.pid=%s"%p1.pid)
  print("p2.name=%s"%p2.name)
  print("p2.pid=%s"%p2.pid)
  print("------等待子进程-------")
  # 等待p1进程结束
  p1.join()
  # 等待p2进程结束
  p2.join() 
  print("------父进程执行结束-------")

结果:

------父进程开始执行-------
父进程PID:2512
p1.is_alive=True
p2.is_alive=True
p1.name=mrsoft
p1.pid=20328
p2.name=SubProcess-2
p2.pid=13700
------等待子进程-------
子进程(20328) 开始执行,父进程为(2512)
子进程(13700) 开始执行,父进程为(2512)
子进程(20328)执行结束,耗时1.00秒
子进程(13700)执行结束,耗时2.00秒
------父进程执行结束-------

上述代码中,定义了一个SubProcess子类,继承multiprocess.Process父类。SubProcess子类中定义了两个方法:__init__()初始化方法和run()方法,在__init__()初始化方法中,调用父类multiprocess.Process的__init__()初始化方法,否则父类的__init__()方法会被覆盖,无法开启进程。此外,在SubProcess子类中没有定义start()方法,但在主程序中却调用了start()方法,此时就会自动执行SubProcess类的run()方法。

3、使用进程池Pool创建进程

上面我们使用Process类创建了两个进程,但如果要创建十几个或者上百个进程,则需要实例化更多的Process类,解决这一问题的方法就是使用multiprocessing模块提供的pool类,即Pool进程池。

我们先来了解下Pool类的常用方法:

apply_async(func[,args[,kwds]]):使用非阻塞方式调用func()函数(并行执行,阻塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func()函数的参数列表, kwds为传递给func()函数的关键字参数列表

apply(func[,args[,kwds]]):使用阻塞方式调用func()函数

close():关闭Pool,使其不再接受新的任务

terminate():不管任务是否完成,立即终止

join():主进程阻塞,等待子进程的退出,必须在close或terminate之后使用

下面通过一个示例演示一下如何通过进程池创建多进程,设置最大进程数为3,使用非阻塞方式执行10个任务:

# -*- coding=utf-8 -*-
from multiprocessing import Pool
import os, time

def task(name):
  print('子进程(%s)执行task %s ...' % ( os.getpid() ,name))
  # 休眠1秒
  time.sleep(1)    

if __name__=='__main__':
  print('父进程(%s).' % os.getpid())
  # 定义一个进程池,最大进程数3
  p = Pool(3)    
  # 从0开始循环10次  
  for i in range(10):
    # 使用非阻塞方式调用task()函数 
    p.apply_async(task, args=(i,))  
  print('等待所有子进程结束...')
  # 关闭进程池,关闭后p不再接收新的请求
  p.close()
  # 等待子进程结束
  p.join()  
  print('所有子进程结束.')

结果:

父进程(3856).
等待所有子进程结束...
子进程(18872)执行task 0 ...
子进程(11220)执行task 1 ...
子进程(10140)执行task 2 ...
子进程(18872)执行task 3 ...
子进程(11220)执行task 4 ...
子进程(10140)执行task 5 ...
子进程(18872)执行task 6 ...
子进程(11220)执行task 7 ...
子进程(10140)执行task 8 ...
子进程(18872)执行task 9 ...
所有子进程结束.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中利用sorted()函数排序的简单教程
Apr 27 Python
TensorFlow安装及jupyter notebook配置方法
Sep 08 Python
Python2.7+pytesser实现简单验证码的识别方法
Dec 29 Python
python 异或加密字符串的实例
Oct 14 Python
DataFrame:通过SparkSql将scala类转为DataFrame的方法
Jan 29 Python
在python里协程使用同步锁Lock的实例
Feb 19 Python
pycharm运行程序时看不到任何结果显示的解决
Feb 21 Python
python实现交并比IOU教程
Apr 16 Python
浅谈Python程序的错误:变量未定义
Jun 02 Python
Python getattr()函数使用方法代码实例
Aug 10 Python
python入门教程之基本算术运算符
Nov 13 Python
如何基于python实现单目三维重建详解
Jun 25 Python
keras model.fit 解决validation_spilt=num 的问题
Jun 19 #Python
为什么是 Python -m
Jun 19 #Python
Python 私有属性和私有方法应用场景分析
Jun 19 #Python
Python基于network模块制作电影人物关系图
Jun 19 #Python
keras中的History对象用法
Jun 19 #Python
python中rc1什么意思
Jun 19 #Python
解决keras backend 越跑越慢问题
Jun 18 #Python
You might like
解析PHP中empty is_null和isset的测试
2013/06/29 PHP
浅谈PHP中Stream(流)
2015/06/08 PHP
php中define用法实例
2015/07/30 PHP
PHP判断上传文件类型的解决办法
2015/10/20 PHP
php实现简单的上传进度条
2015/11/17 PHP
详解Laravel服务容器的绑定与解析
2019/11/05 PHP
jQuery1.6 类型判断实现代码
2011/09/01 Javascript
设置checkbox为只读(readOnly)的两种方式
2013/10/11 Javascript
微信分享的标题、缩略图、连接及描述设置方法
2014/10/14 Javascript
jQuery简单实现提交数据出现loading进度条的方法
2016/03/29 Javascript
总结十个Angular.js由浅入深的面试问题
2016/08/26 Javascript
第一次接触Bootstrap框架
2016/10/24 Javascript
浅谈React 属性和状态的一些总结
2016/11/21 Javascript
基于JS对象创建常用方式及原理分析
2017/06/28 Javascript
深入讲解xhr(XMLHttpRequest)/jsonp请求之abort
2017/07/26 Javascript
Angular实现的进度条功能示例
2018/02/18 Javascript
JS实现带阴历的日历功能详解
2019/01/24 Javascript
浅谈webpack和webpack-cli模块源码分析
2020/01/19 Javascript
[10:28]2018DOTA2国际邀请赛寻真——VGJ.S寻梦之路
2018/08/15 DOTA
Python对两个有序列表进行合并和排序的例子
2014/06/13 Python
python实现的简单RPG游戏流程实例
2015/06/28 Python
Python编程中实现迭代器的一些技巧小结
2016/06/21 Python
python 利用for循环 保存多个图像或者文件的实例
2018/11/09 Python
python3连接mysql获取ansible动态inventory脚本
2020/01/19 Python
IE兼容css3圆角的实现代码
2011/07/21 HTML / CSS
美国皮靴公司自1863年:The Frye Company
2016/11/30 全球购物
英国外籍人士的在线超市:British Corner Shop
2019/06/03 全球购物
两道JAVA笔试题
2016/09/14 面试题
学前教育教师求职自荐信
2013/09/22 职场文书
中医专业职业生涯规划书范文
2014/01/04 职场文书
销售业务员岗位职责
2014/01/29 职场文书
2014年开学第一课活动方案
2014/03/06 职场文书
给公司的建议书范文
2014/05/13 职场文书
2014卖家双十一活动策划书
2014/09/29 职场文书
2015年财务经理工作总结
2015/05/13 职场文书
详解Go语言中配置文件使用与日志配置
2022/06/01 Golang