详解python之多进程和进程池(Processing库)


Posted in Python onJune 09, 2017

环境:win7+python2.7

一直想学习多进程或多线程,但之前只是单纯看一点基础知识还有简单的介绍,无法理解怎么去应用,直到前段时间看了github的一个爬虫项目涉及到多进程,多线程相关内容,一边看一边百度相关知识点,现在把一些相关知识点和一些应用写下来做个记录.

首先说下什么是进程:进程是程序在计算机上的一次执行活动,当运行一个程序的时候,就启动了一个进程.而进程又分为系统进程和用户进程.只要是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运行状态下的操作系统本身;而所有由你启动的进程都是用户进程。进程是操作系统进行资源分配的单位。

直观点说,在任务管理器的用户名上标明system的是系统进程,标明administrator的是用户进程,另外net是网洛,lcacal service是本地服务,关于进程更加具体的信息可以百科,这里得省点力气,不然收不回了.

一.多进程的简单使用

如图,multiprocessing有多个函数,很多我也还没去了解,这里只讲我目前了解的.

详解python之多进程和进程池(Processing库)

进程创建:Process(target=主要运行的函数,name=自定义进程名称可不写,args=(参数))

方法:

  1. is_alive():判断进程是否存活
  2. join([timeout]):子进程结束再执行下一步,timeout为超时时间,有时进程遇到阻塞,为了程序能够运行下去而设置超时时间
  3. run():如果在创建Process对象的时候不指定target,那么就会默认执行Process的run方法
  4. start():启动进程,区分run()
  5. terminate():终止进程,关于终止进程没有这么简单,貌似用psutil包会更好,有机会以后了解更多再写下。

其中,Process以start()启动某个进程。

属性:

  1. authkey: 在文档中authkey()函数找到这么一句话:Set authorization key of process设置过程的授权密钥 ,目前没找到相关应用实例,这个密钥是怎么用的呢?文章不提
  2. daemon:父进程终止后自动终止,且自己不能产生新进程,必须在start()之前设置
  3. exitcode:进程在运行时为None、如果为?N,表示被信号N结束
  4. name:进程的名字,自定义
  5. pid:每个进程有唯一的PID编号。

1.Process(),start(),join()

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 p1=Process(target=fun1,args=(4,))
 p2 = Process(target=fun2, args=(6,))
 p1.start()
 p2.start()
 p1.join()
 p2.join()
 b=time.time()
 print 'finish',b-a

这里一共开了两个进程,p1和p2,arg=(4,)中的4是fun1函数的参数,这里要用tulpe类型,如果两个参数或更多就是arg=(参数1,参数2...),之后用start()启动进程,我们设置等待p1和p2进程结束再执行下一步.来看下面的运行结果,fun2和fun1基本在同一时间开始运行,当运行完毕(fun1睡眠4秒,同时fun2睡眠6秒),才执行print 'finish',b-a语句

this is fun2 Mon Jun 05 13:48:04 2017
this is fun1 Mon Jun 05 13:48:04 2017
fun1 finish Mon Jun 05 13:48:08 2017
fun2 finish Mon Jun 05 13:48:10 2017
finish 6.20300006866

Process finished with exit code 0

我们再来看下start()与join()处于不同位置会发生什么

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 p1=Process(target=fun1,args=(4,))
 p2 = Process(target=fun2, args=(6,))
 p1.start()
 p1.join()
 p2.start()
 p2.join()
 b=time.time()
 print 'finish',b-a

结果:

this is fun1 Mon Jun 05 14:19:28 2017
fun1 finish Mon Jun 05 14:19:32 2017
this is fun2 Mon Jun 05 14:19:32 2017
fun2 finish Mon Jun 05 14:19:38 2017
finish 10.1229999065

Process finished with exit code 0

看,现在是先运行fun1函数,运行完毕再运行fun2接着再是print 'finish',即先运行进程p1再运行进程p2,感受到join()的魅力了吧.现在再试试注释掉join()看看又会出现什么

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 p1=Process(target=fun1,args=(4,))
 p2 = Process(target=fun2, args=(6,))
 p1.start()
 p2.start()
 p1.join()
 #p2.join()
 b=time.time()
 print 'finish',b-a

结果:

this is fun1 Mon Jun 05 14:23:57 2017
this is fun2 Mon Jun 05 14:23:58 2017
fun1 finish Mon Jun 05 14:24:01 2017
finish 4.05900001526
fun2 finish Mon Jun 05 14:24:04 2017

Process finished with exit code 0

这次是运行完fun1(因为p1进程有用join(),所以主程序等待p1运行完接着执行下一步),接着继续运行主进程的print 'finish',最后fun2运行完毕才结束

2.name,daemon,is_alive():

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 p1=Process(name='fun1进程',target=fun1,args=(4,))
 p2 = Process(name='fun2进程',target=fun2, args=(6,))
 p1.daemon=True
 p2.daemon = True
 p1.start()
 p2.start()
 p1.join()
 print p1,p2
 print '进程1:',p1.is_alive(),'进程2:',p2.is_alive()
 #p2.join()
 b=time.time()
 print 'finish',b-a

结果:

this is fun2 Mon Jun 05 14:43:49 2017
this is fun1 Mon Jun 05 14:43:49 2017
fun1 finish Mon Jun 05 14:43:53 2017
<Process(fun1进程, stopped daemon)> <Process(fun2进程, started daemon)>
进程1: False 进程2: True
finish 4.06500005722

Process finished with exit code 0

可以看到,name是给进程赋予名字, 运行到print '进程1:',p1.is_alive(),'进程2:',p2.is_alive() 这句的时候,p1进程已经结束(返回False),p2进程仍然在运行(返回True),但p2没有用join(),所以直接接着执行主进程,由于用了daemon=Ture,父进程终止后自动终止,p2进程没有结束就强行结束整个程序了.

3.run()

run()在Process没有指定target函数时,默认用run()函数运行程序,

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a = time.time()
 p=Process()
 p.start()
 p.join()
 b = time.time()
 print 'finish', b - a

结果:

finish 0.0840001106262

从结果看出,进程p什么也没做,为了让进程正常运行,我们酱紫写:

目标函数没有参数:

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

def fun1():
 print 'this is fun1',time.ctime()
 time.sleep(2)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a = time.time()
 p=Process()
 p.run=fun1
 p.start()
 p.join()
 b = time.time()
 print 'finish', b - a

结果:

this is fun1 Mon Jun 05 16:34:41 2017
fun1 finish Mon Jun 05 16:34:43 2017
finish 2.11500000954

Process finished with exit code 0

目标函数有参数:

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a = time.time()
 p=Process()
 p.run=fun1(2)
 p.start()
 p.join()
 b = time.time()
 print 'finish', b - a

结果:

this is fun1 Mon Jun 05 16:36:27 2017
fun1 finish Mon Jun 05 16:36:29 2017
Process Process-1:
Traceback (most recent call last):
 File "E:\Anaconda2\lib\multiprocessing\process.py", line 258, in _bootstrap
 self.run()
TypeError: 'NoneType' object is not callable
finish 2.0529999733

Process finished with exit code 0

目标函数有参数的出现了异常,为什么呢?我现在还找不到原因,但是实践发现,当最后一个参数赋予进程运行后,没有其他参数,就会出现这个异常,有人知道的望告知.

二.进程池

对于需要使用几个甚至十几个进程时,我们使用Process还是比较方便的,但是如果要成百上千个进程,用Process显然太笨了,multiprocessing提供了Pool类,即现在要讲的进程池,能够将众多进程放在一起,设置一个运行进程上限,每次只运行设置的进程数,等有进程结束,再添加新的进程

Pool(processes =num):设置运行进程数,当一个进程运行完,会添加新的进程进去

apply_async(函数,(参数)):非阻塞,其中参数是tulpe类型,

apply(函数,(参数)):阻塞

close():关闭pool,不能再添加新的任务

terminate():结束运行的进程,不再处理未完成的任务

join():和Process介绍的作用一样, 但要在close或terminate之后使用。

1.单个进程池

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 pool = Pool(processes =3) # 可以同时跑3个进程
 for i in range(3,8):
  pool.apply_async(fun1,(i,))
 pool.close()
 pool.join()
 b=time.time()
 print 'finish',b-a

结果:

this is fun1 Mon Jun 05 15:15:38 2017
this is fun1 Mon Jun 05 15:15:38 2017
this is fun1 Mon Jun 05 15:15:38 2017
fun1 finish Mon Jun 05 15:15:41 2017
this is fun1 Mon Jun 05 15:15:41 2017
fun1 finish Mon Jun 05 15:15:42 2017
this is fun1 Mon Jun 05 15:15:42 2017
fun1 finish Mon Jun 05 15:15:43 2017
fun1 finish Mon Jun 05 15:15:47 2017
fun1 finish Mon Jun 05 15:15:49 2017
finish 11.1370000839

Process finished with exit code 0

从上面的结果可以看到,设置了3个运行进程上限,15:15:38这个时间同时开始三个进程,当第一个进程结束时(参数为3秒那个进程),会添加新的进程,如此循环,直至进程池运行完再执行主进程语句b=time.time() print 'finish',b-a .这里用到非阻塞apply_async(),再来对比下阻塞apply()

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 pool = Pool(processes =3) # 可以同时跑3个进程
 for i in range(3,8):
  pool.apply(fun1,(i,))
 pool.close()
 pool.join()
 b=time.time()
 print 'finish',b-a

结果:

this is fun1 Mon Jun 05 15:59:26 2017
fun1 finish Mon Jun 05 15:59:29 2017
this is fun1 Mon Jun 05 15:59:29 2017
fun1 finish Mon Jun 05 15:59:33 2017
this is fun1 Mon Jun 05 15:59:33 2017
fun1 finish Mon Jun 05 15:59:38 2017
this is fun1 Mon Jun 05 15:59:38 2017
fun1 finish Mon Jun 05 15:59:44 2017
this is fun1 Mon Jun 05 15:59:44 2017
fun1 finish Mon Jun 05 15:59:51 2017
finish 25.1610000134

Process finished with exit code 0

可以看到,阻塞是当一个进程结束后,再进行下一个进程,一般我们都用非阻塞apply_async()

2.多个进程池

上面是使用单个进程池的,对于多个进程池,我们可以用for循环,直接看代码

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

def fun1(t):
 print 'this is fun1',time.ctime()
 time.sleep(t)
 print 'fun1 finish',time.ctime()

def fun2(t):
 print 'this is fun2',time.ctime()
 time.sleep(t)
 print 'fun2 finish',time.ctime()

if __name__ == '__main__':
 a=time.time()
 pool = Pool(processes =3) # 可以同时跑3个进程
 for fun in [fun1,fun2]:
  for i in range(3,8):
   pool.apply_async(fun,(i,))
 pool.close()
 pool.join()
 b=time.time()
 print 'finish',b-a

结果:

this is fun1 Mon Jun 05 16:04:38 2017
this is fun1 Mon Jun 05 16:04:38 2017
this is fun1 Mon Jun 05 16:04:38 2017
fun1 finish Mon Jun 05 16:04:41 2017
this is fun1 Mon Jun 05 16:04:41 2017
fun1 finish Mon Jun 05 16:04:42 2017
this is fun1 Mon Jun 05 16:04:42 2017
fun1 finish Mon Jun 05 16:04:43 2017
this is fun2 Mon Jun 05 16:04:43 2017
fun2 finish Mon Jun 05 16:04:46 2017
this is fun2 Mon Jun 05 16:04:46 2017
fun1 finish Mon Jun 05 16:04:47 2017
this is fun2 Mon Jun 05 16:04:47 2017
fun1 finish Mon Jun 05 16:04:49 2017
this is fun2 Mon Jun 05 16:04:49 2017
fun2 finish Mon Jun 05 16:04:50 2017
this is fun2 Mon Jun 05 16:04:50 2017
fun2 finish Mon Jun 05 16:04:52 2017
fun2 finish Mon Jun 05 16:04:55 2017
fun2 finish Mon Jun 05 16:04:57 2017
finish 19.1670000553

Process finished with exit code 0

看到了,在fun1运行完接着运行fun2.

另外对于没有参数的情况,就直接 pool.apply_async(funtion),无需写上参数.

在学习编写程序过程,曾遇到不用if _name_ == '_main_':而直接运行程序,这样结果会出错,经查询,在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的if _name_ == ‘_main_' :语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要。原因有人这么说:在执行的?r候,由于你写的 py 会被当成module 读进执行。所以,一定要判断自身是否为 _main_。也就是要:

if __name__ == ‘__main__' :
# do something.

这里我自己还搞不清楚,期待以后能够理解

学习的过程中,还涉及了经常和进程一起运用的队列Queue和线程threading,有时间以后再写吧,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
利用python编写一个图片主色转换的脚本
Dec 07 Python
可能是最全面的 Python 字符串拼接总结【收藏】
Jul 09 Python
python 实现对数据集的归一化的方法(0-1之间)
Jul 17 Python
详解Python发送email的三种方式
Oct 18 Python
在PyCharm中批量查找及替换的方法
Jan 20 Python
python将视频转换为全字符视频
Apr 26 Python
六行python代码的爱心曲线详解
May 17 Python
Python实现Selenium自动化Page模式
Jul 14 Python
keras处理欠拟合和过拟合的实例讲解
May 25 Python
python tkiner实现 一个小小的图片翻页功能的示例代码
Jun 24 Python
python之语音识别speech模块
Sep 09 Python
理解python中装饰器的作用
Jul 21 Python
Python使用django搭建web开发环境
Jun 09 #Python
Python实现删除文件中含“指定内容”的行示例
Jun 09 #Python
Python实现两个list对应元素相减操作示例
Jun 09 #Python
Python实现向服务器请求压缩数据及解压缩数据的方法示例
Jun 09 #Python
python爬虫框架talonspider简单介绍
Jun 09 #Python
python实现list元素按关键字相加减的方法示例
Jun 09 #Python
Python利用QQ邮箱发送邮件的实现方法(分享)
Jun 09 #Python
You might like
php的ajax框架xajax入门与试用介绍
2010/12/19 PHP
smarty中js的调用方法示例
2014/10/27 PHP
php打印输出棋盘的实现方法
2014/12/23 PHP
Symfony的安装和配置方法
2016/03/17 PHP
学习YUI.Ext 第四天--对话框Dialog的使用
2007/03/10 Javascript
js鼠标点击事件在各个浏览器中的写法及Event对象属性介绍
2013/01/24 Javascript
jQuery表格插件datatables用法总结
2014/09/05 Javascript
jQuery遍历对象、数组、集合实例
2014/11/08 Javascript
javascript中typeof操作符和constucor属性检测
2015/02/26 Javascript
深入理解JavaScript的React框架的原理
2015/07/02 Javascript
基于jQuery实现返回顶部实例代码
2016/01/01 Javascript
jQuery使用中可能被XSS攻击的一些危险环节提醒
2016/05/24 Javascript
又一枚精彩的弹幕效果jQuery实现
2016/07/25 Javascript
jQuery实现jQuery-form.js实现异步上传文件
2017/04/28 jQuery
React Js 微信禁止复制链接分享禁止隐藏右上角菜单功能
2017/05/26 Javascript
微信小程序实现图片上传、删除和预览功能的方法
2017/12/18 Javascript
如何在vue里添加好看的lottie动画
2018/08/02 Javascript
详解Vue 全局变量,局部变量
2019/04/17 Javascript
微信小程序开发注意指南和优化实践(小结)
2019/06/21 Javascript
微信小程序使用canvas自适应屏幕画海报并保存图片功能
2019/07/25 Javascript
[01:09:16]DOTA2-DPC中国联赛 正赛 SAG vs Dynasty BO3 第一场 1月25日
2021/03/11 DOTA
python中的sort方法使用详解
2014/07/25 Python
Python中threading模块join函数用法实例分析
2015/06/04 Python
Python编程求质数实例代码
2018/01/31 Python
Python实现批量读取图片并存入mongodb数据库的方法示例
2018/04/02 Python
对pandas中iloc,loc取数据差别及按条件取值的方法详解
2018/11/06 Python
Python Celery多队列配置代码实例
2019/11/22 Python
使用tensorflow实现矩阵分解方式
2020/02/07 Python
Python之京东商品秒杀的实现示例
2021/01/06 Python
纯CSS3大转盘抽奖示例代码(响应式、可配置)
2017/01/13 HTML / CSS
纯css3实现思维导图样式示例
2018/11/01 HTML / CSS
德国珠宝和配件商店:Styleserver
2021/02/23 全球购物
介绍一些UNIX常用简单命令
2014/11/11 面试题
公司员工违纪检讨书
2015/05/05 职场文书
MYSQL(电话号码,身份证)数据脱敏的实现
2021/05/28 MySQL
Golang map映射的用法
2022/04/22 Golang