通过实例解析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 urllib、urllib2、httplib抓取网页代码实例
May 09 Python
Python 列表排序方法reverse、sort、sorted详解
Jan 22 Python
从局部变量和全局变量开始全面解析Python中变量的作用域
Jun 16 Python
django基础之数据库操作方法(详解)
May 24 Python
python3实现UDP协议的服务器和客户端
Jun 14 Python
pandas把dataframe转成Series,改变列中值的类型方法
Apr 10 Python
Python实现将Excel转换成为image的方法
Oct 23 Python
Python自动化之数据驱动让你的脚本简洁10倍【推荐】
Jun 04 Python
用Python解数独的方法示例
Oct 24 Python
Tensorflow 定义变量,函数,数值计算等名字的更新方式
Feb 10 Python
Python基于当前时间批量创建文件
May 07 Python
python实现双人五子棋(终端版)
Dec 30 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的库,结果发现很多东西
2006/12/31 PHP
VIM中设置php自动缩进为4个空格的方法详解
2013/06/14 PHP
php CI框架插入一条或多条sql记录示例
2014/07/29 PHP
精心挑选的15个jQuery下拉菜单制作教程
2012/06/15 Javascript
js购物车实现思路及代码(个人感觉不错)
2013/12/23 Javascript
jQuery拖拽 & 弹出层 介绍与示例
2013/12/27 Javascript
js判断是否为ie的方法小结
2014/01/13 Javascript
动态加载JavaScript文件的两种方法
2016/04/22 Javascript
一个简单不报错的summernote 图片上传案例
2016/07/11 Javascript
JS实现探测网站链接的方法【测试可用】
2016/11/08 Javascript
正则 js分转元带千分符号详解
2017/03/08 Javascript
Dropify.js图片宽高自适应的方法
2017/11/27 Javascript
vue.js vue-router如何实现无效路由(404)的友好提示
2017/12/20 Javascript
使用vue-aplayer插件时出现的问题的解决
2018/03/02 Javascript
解决vue-cli3 使用子目录部署问题
2018/07/19 Javascript
video.js 实现视频只能后退不能快进的思路详解
2018/08/09 Javascript
解决Js先触发失去焦点事件再执行点击事件的问题
2018/08/30 Javascript
jQuery实现的分页插件完整示例
2020/05/26 jQuery
Python 含参构造函数实例详解
2017/05/25 Python
Python打印输出数组中全部元素
2018/03/13 Python
Django获取model中的字段名和字段的verbose_name方式
2020/05/19 Python
python实现企业微信定时发送文本消息的示例代码
2020/11/24 Python
python自动从arxiv下载paper的示例代码
2020/12/05 Python
纯CSS3实现自定义Tooltip边框涂鸦风格的教程
2014/11/05 HTML / CSS
Timberland德国官网:靴子、鞋子、衣服、夹克及配件
2019/12/10 全球购物
通用求职信范文模板分享
2013/12/27 职场文书
酒店总经理助理职责
2014/02/12 职场文书
《我的第一本书》教学反思
2014/02/15 职场文书
《我要的是葫芦》教学反思
2014/02/23 职场文书
国际商贸专业自荐信
2014/06/09 职场文书
物理课外活动总结
2014/08/27 职场文书
金融保险专业求职信
2014/09/03 职场文书
校运动会广播稿300字
2014/10/07 职场文书
5.12护士节活动总结
2015/02/10 职场文书
小学校长开学致辞
2015/07/29 职场文书
使用 DataAnt 监控 Apache APISIX的原理解析
2022/07/07 Servers