python实现多进程代码示例


Posted in Python onOctober 31, 2018

想要充分利用多核CPU资源,Python中大部分情况下都需要使用多进程,Python中提供了multiprocessing这个包实现多进程。multiprocessing支持子进程、进程间的同步与通信,提供了Process、Queue、Pipe、Lock等组件。

开辟子进程

multiprocessing中提供了Process类来生成进程实例

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

  • group分组,实际上不使用
  • target表示调用对象,你可以传入方法的名字
  • args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m, n)即可
  • kwargs表示调用对象的字典
  • name是别名,相当于给这个进程取一个名字

先来个小例子:

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


def run_proc(wTime):
  n = 0
  while n < 3:
    print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())  #获取当前进程号和正在运行是的时间
    time.sleep(wTime)  #等待(休眠)
    n += 1

if __name__ == "__main__":
  p = Process(target=run_proc, args=(2,)) #申请子进程
  p.start()   #运行进程
  print "Parent process run. subProcess is ", p.pid
  print "Parent process end,{0}".format(time.ctime())

运行结果:

Parent process run. subProcess is 30196
Parent process end,Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:23 2017
subProcess 30196 run, Mon Mar 27 11:20:25 2017

根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸( zombie)进程。

通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。

有什么办法可以避免僵尸进程呢?

这里介绍进程的一个属性 deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。
所以给上面的程序加上p.deamon = true,看看效果。

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


def run_proc(wTime):
  n = 0
  while n < 3:
    print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
    time.sleep(wTime)
    n += 1

if __name__ == "__main__":
  p = Process(target=run_proc, args=(2,))
  p.daemon = True  #加入daemon
  p.start()
  print "Parent process run. subProcess is ", p.pid
  print "Parent process end,{0}".format(time.ctime())

执行结果:

Parent process run. subProcess is 31856
Parent process end,Mon Mar 27 11:40:10 2017

这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?

这里引入p.join()方法,它使子进程执行结束后,父进程才执行之后的代码

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


def run_proc(wTime):
  n = 0
  while n < 3:
    print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
    time.sleep(wTime)
    n += 1

if __name__ == "__main__":
  p = Process(target=run_proc, args=(2,))
  p.daemon = True
  p.start()
  p.join()  #加入join方法
  print "Parent process run. subProcess is ", p.pid
  print "Parent process end,{0}".format(time.ctime())

执行结果:

subProcess 32076 run, Mon Mar 27 11:46:07 2017
subProcess 32076 run, Mon Mar 27 11:46:09 2017
subProcess 32076 run, Mon Mar 27 11:46:11 2017
Parent process run. subProcess is 32076
Parent process end,Mon Mar 27 11:46:13 2017

这样所有的进程就能顺利的执行了。

将进程定义成类

通过继承Process类,来自定义进程类,实现run方法。实例p通过调用p.start()时自动调用run方法。

如下:

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


class Myprocess(Process):

  def __init__(self, wTime):
    Process.__init__(self)
    self.wTime = wTime

  def run(self):
    n = 0
    while n < 3:
      print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
      time.sleep(self.wTime)
      n += 1


if __name__ == "__main__":
  p = Myprocess(2)
  p.daemon = True
  p.start()  #自动调用run方法
  p.join()
  print "Parent process run. subProcess is ", p.pid
  print "Parent process end,{0}".format(time.ctime())

执行结果和上一个例子相同。

创建多个进程

很多时候系统都需要创建多个进程以提高CPU的利用率,当数量较少时,可以手动生成一个个Process实例。当进程数量很多时,或许可以利用循环,但是这需要程序员手动管理系统中并发进程的数量,有时会很麻烦。这时进程池Pool就可以发挥其功效了。可以通过传递参数限制并发进程的数量,默认值为CPU的核数。

直接上例子:

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

def run_proc(name):    ##定义一个函数用于进程调用
  for i in range(5):  
    time.sleep(0.2)  #休眠0.2秒
    print 'Run child process %s (%s)' % (name, os.getpid())
#执行一次该函数共需1秒的时间

if __name__ =='__main__': #执行主进程
  print 'Run the main process (%s).' % (os.getpid())
  mainStart = time.time() #记录主进程开始的时间
  p = Pool(8)      #开辟进程池
  for i in range(16):                 #开辟14个进程
    p.apply_async(run_proc,args=('Process'+str(i),))#每个进程都调用run_proc函数,
                            #args表示给该函数传递的参数。

  print 'Waiting for all subprocesses done ...'
  p.close() #关闭进程池
  p.join() #等待开辟的所有进程执行完后,主进程才继续往下执行
  print 'All subprocesses done'
  mainEnd = time.time() #记录主进程结束时间
  print 'All process ran %0.2f seconds.' % (mainEnd-mainStart) #主进程执行时间

执行结果:

开头部分

Run the main process (30920).
Waiting for all subprocesses done …
Run child process Process0 (32396)
Run child process Process3 (25392)
Run child process Process1 (28732)
Run child process Process2 (32436)

末尾部分:

Run child process Process15 (25880)
All subprocesses done
All process last 2.49 seconds.

相关说明:

这里进程池对并发进程的限制数量为8个,而程序运行时会产生16个进程,进程池将自动管理系统内进程的并发数量,其余进程将会在队列中等待。限制并发数量是因为,系统中并发的进程不是越多越好,并发进程太多,可能使CPU大部分的时间用于进程调度,而不是执行有效的计算。

采用多进程并发技术时,就单个处理机而言,其对进程的执行是串行的。但具体某个时刻哪个进程获得CPU资源而执行是不可预知的(如执行结果的开头部分,各进程的执行顺序不定),这就体现了进程的异步性。

如果单个程序执行14次run_proc函数,那么它会需要至少16秒,通过进程的并发,这里只需要2.49秒,可见并发的优势。

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

Python 相关文章推荐
Python 元组(Tuple)操作详解
Mar 11 Python
Python中使用Tkinter模块创建GUI程序实例
Jan 14 Python
python通过colorama模块在控制台输出彩色文字的方法
Mar 19 Python
Python中Django框架利用url来控制登录的方法
Jul 25 Python
python使用arcpy.mapping模块批量出图
Mar 06 Python
python 递归遍历文件夹,并打印满足条件的文件路径实例
Aug 30 Python
解决Tensorflow安装成功,但在导入时报错的问题
Jun 13 Python
解决PySide+Python子线程更新UI线程的问题
Jan 11 Python
线程安全及Python中的GIL原理分析
Oct 29 Python
使用Keras加载含有自定义层或函数的模型操作
Jun 10 Python
Python3爬虫里关于代理的设置总结
Jul 30 Python
Matplotlib绘制混淆矩阵的实现
May 27 Python
Python UnboundLocalError和NameError错误根源案例解析
Oct 31 #Python
python多进程控制学习小结
Oct 31 #Python
在Python中实现替换字符串中的子串的示例
Oct 31 #Python
python创建文件时去掉非法字符的方法
Oct 31 #Python
python3 中文乱码与默认编码格式设定方法
Oct 31 #Python
解决python中 f.write写入中文出错的问题
Oct 31 #Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
Oct 30 #Python
You might like
全国FM电台频率大全 - 1 北京市
2020/03/11 无线电
解析PHPExcel使用的常用说明以及把PHPExcel整合进CI框架的介绍
2013/06/24 PHP
Server.HTMLEncode让代码在页面里显示为源代码
2013/12/08 PHP
destoon实现不同会员组公司名称显示不同的颜色的方法
2014/08/22 PHP
PHP实现在线阅读PDF文件的方法
2015/06/23 PHP
PHP生成唯一ID之SnowFlake算法
2016/12/17 PHP
PHP编程快速实现数组去重的方法详解
2017/07/22 PHP
js 函数的副作用分析
2011/08/23 Javascript
ajax处理php返回json数据的实例代码
2013/01/24 Javascript
JS实现遮罩层效果的简单实例
2013/11/12 Javascript
js实现按钮加背景图片常用方法
2014/11/01 Javascript
JavaScript中的值类型详细介绍
2014/12/29 Javascript
JavaScript如何实现对数字保留两位小数一位自动补零
2015/12/18 Javascript
基于Echarts 3.19 制作常用的图形(非静态)
2016/05/19 Javascript
jQuery学习笔记之回调函数
2016/08/15 Javascript
Vue+axios 实现http拦截及路由拦截实例
2017/04/25 Javascript
JS模拟实现哈希表及应用详解
2018/05/04 Javascript
Node.js中你不可不精的Stream(流)
2018/06/08 Javascript
微信小程序云开发之模拟后台增删改查
2019/05/16 Javascript
js+css实现全屏侧边栏
2020/06/16 Javascript
从零开始学Python第八周:详解网络编程基础(socket)
2016/12/14 Python
Python实现的json文件读取及中文乱码显示问题解决方法
2018/08/06 Python
python绘制简单彩虹图
2018/11/19 Python
Python编写合并字典并实现敏感目录的小脚本
2019/02/26 Python
django celery redis使用具体实践
2019/04/08 Python
在flask中使用python-dotenv+flask-cli自定义命令(推荐)
2020/01/05 Python
Python进行统计建模
2020/08/10 Python
python利用pytesseract 实现本地识别图片文字
2020/12/14 Python
selenium设置浏览器为headless无头模式(Chrome和Firefox)
2021/01/08 Python
卡骆驰英国官网:Crocs英国
2019/08/22 全球购物
十佳班主任事迹材料
2014/01/18 职场文书
教师现实表现材料
2014/02/14 职场文书
经典演讲稿开场白
2014/08/25 职场文书
家长给老师的感谢信
2015/01/20 职场文书
杨善洲观后感
2015/06/04 职场文书
医院岗前培训心得体会
2016/01/08 职场文书