python多进程控制学习小结


Posted in Python onOctober 31, 2018

前言:

python多进程,经常在使用,却没有怎么系统的学习过,官网上面讲得比较细,结合自己的学习,整理记录下官网:https://docs.python.org/3/library/multiprocessing.html

multiprocessing简介

multiprocessing是python自带的多进程模块,可以大批量的生成进程,在服务器为多核CPU时效果更好,类似于threading模块。相对于多线程,多进程由于独享内存空间,更稳定安全,在运维里面做些批量操作时,多进程有更多适用的场景

multiprocessing包提供了本地和远程两种并发操作,有效的避开了使用子进程而不是全局解释锁的线程,因此,multiprocessing可以有效利用到多核处理

Process类

在multiporcessing中,通过Process类对象来批量产生进程,使用start()方法来启动这个进程

1.语法

multiprocessing.Process(group=None,target=None,name=None,args=(),kwargs={},*)

  • group: 这个参数一般为空,它只是为了兼容threading.Tread
  • target: 这个参数就是通过run()可调用对象的方法,默认为空,表示没有方法被调用
  • name: 表示进程名
  • args: 传给target调用方法的tuple(元组)参数
  • kwargs: 传给target调用方法的dict(字典)参数

2.Process类的方法及对象

run()
该方法是进程的运行过程,可以在子类中重写此方法,一般也很少去重构

start()
启动进程,每个进程对象都必须被该方法调用

join([timeout])
等待进程终止,再往下执行,可以设置超时时间

name
可以获取进程名字,多个进程也可以是相同的名字

is_alive()
返回进程是否还存活,True or False,进程存活是指start()开始到子进程终止

daemon
守护进程的标记,一个布尔值,在start()之后设置该值,表示是否后台运行
注意:如果设置了后台运行,那么后台程序不运行再创建子进程

pid
可以获取进程ID

exitcode
子进程退出时的值,如果进程还没有终止,值将是None,如果是负值,表示子进程被终止

terminate()
终止进程,如果是Windows,则使用terminateprocess(),该方法对已经退出和结束的进程,将不会执行

以下为一个简单的例子:

#-*- coding:utf8 -*- 
import multiprocessing
import time

def work(x):
  time.sleep(1)
  print time.ctime(),'这是子进程[{0}]...'.format(x)

if __name__ == '__main__':
  for i in range(5):
    p = multiprocessing.Process(target=work,args=(i,))
    print '启动进程数:{0}'.format(i)
    p.start()
    p.deamon = True

python多进程控制学习小结

当然也可以显示每个进程的ID

#-*- coding:utf8 -*- 
import multiprocessing
import time
import os

def work(x):
  time.sleep(1)
  ppid = os.getppid()
  pid = os.getpid()
  print time.ctime(),'这是子进程[{0},父进程:{1},子进程:{2}]...'.format(x,ppid,pid)

if __name__ == '__main__':
  for i in range(5):
    p = multiprocessing.Process(target=work,args=(i,))
    print '启动进程数:{0}'.format(i)
    p.start()
    p.deamon = True

python多进程控制学习小结

但在实际使用的过程中,并不只是并发完就可以了,比如,有30个任务,由于服务器资源有限,每次并发5个任务,这里还涉及到30个任务怎么获取的问题,另外并发的进程任务执行时间很难保证一致,尤其是需要时间的任务,可能并发5个任务,有3个已经执行完了,2个还需要很长时间执行,总不能等到这两个进程执行完了,再继续执行后面的任务,因此进程控制就在此有了使用场景,可以利用Process的方法和一些multiprocessing的包,类等结合使用

进程控制及通信常用类

一、Queue类

类似于python自带的Queue.Queue,主要用在比较小的队列上面

语法:

multiprocessing.Queue([maxsize])

类方法:

qsize()
返回队列的大致大小,因为多进程或者多线程一直在消耗队列,因此该数据不一定正确

empty()
判断队列是否为空,如果是,则返回True,否则False

full()
判断队列是否已满,如果是,则返回True,否则False

put(obj[, block[, timeout]])
将对象放入队列,可选参数block为True,timeout为None

get()
从队列取出对象

#-*- coding:utf8 -*-
from multiprocessing import Process, Queue

def f(q):
  q.put([42,None,'hi'])

if __name__ == '__main__':
  q = Queue()
  p = Process(target=f, args=(q,))
  p.start()
  print q.get() #打印内容: [42,None,'hi']
  p.join()

二、Pipe类

pipe()函数返回一对对象的连接,可以为进程间传输消息,在打印一些日志、进程控制上面有一些用处,Pip()对象返回两个对象connection,代表两个通道,每个connection对象都有send()和recv()方法,需要注意的是两个或以上的进程同时读取或者写入同一管道,可能会导致数据混乱,测试了下,是直接覆盖了。另外,返回的两个connection,如果一个是send()数据,那么另外一个就只能recv()接收数据了

#-*- coding:utf8 -*-
from multiprocessing import Process, Pipe
import time
def f(conn,i):
  print '[{0}]已经执行到子进程:{1}'.format(time.ctime(),i)
  time.sleep(1)
  w = "[{0}]hi,this is :{1}".format(time.ctime(),i)
  conn.send(w)
  conn.close()

if __name__ == '__main__':
  reader = []
  parent_conn, child_conn = Pipe()
  for i in range(4):
    p = Process(target=f, args=(child_conn,i))
    p.start()
    reader.append(parent_conn)
    p.deamon=True

  # 等待所有子进程跑完
  time.sleep(3)
  print '\n[{0}]下面打印child_conn向parent_conn传输的信息:'.format(time.ctime())
  for i in reader:
    print i.recv()

输出为:

python多进程控制学习小结

三、Value,Array

在进行并发编程时,应尽量避免使用共享状态,因为多进程同时修改数据会导致数据破坏。但如果确实需要在多进程间共享数据,multiprocessing也提供了方法Value、Array

from multiprocessing import Process, Value, Array

def f(n, a):
  n.value = 3.1415927
  for i in range(len(a)):
    a[i] = -a[i]

if __name__ == '__main__':
  num = Value('d',0.0)
  arr = Array('i', range(10))

  p = Process(target=f, args=(num, arr))
  p.start()
  p.join()

  print num.value
  print arr[:]

*print
3.1415927
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]*

四、Manager进程管理模块

Manager类管理进程使用得较多,它返回对象可以操控子进程,并且支持很多类型的操作,如: list, dict, Namespace、lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value, Array,因此使用Manager基本上就够了

from multiprocessing import Process, Manager

def f(d, l):
  d[1] = '1'
  d['2'] = 2
  d[0.25] = None
  l.reverse()

if __name__ == '__main__':
  with Manager() as manager:
    d = manager.dict()
    l = manager.list(range(10))

    p = Process(target=f, args=(d, l))
    p.start()
    p.join() #等待进程结束后往下执行
    print d,'\n',l

输出:
{0.25: None, 1: '1', '2': 2}
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

可以看到,跟共享数据一样的效果,大部分管理进程的方法都集成到了Manager()模块了

五、对多进程控制的应用实例

#-*- coding:utf8 -*-
  from multiprocessing import Process, Queue
  import time
  
  def work(pname,q):
    time.sleep(1)
    print_some = "{0}|this is process: {1}".format(time.ctime(),pname)
    print print_some
    q.put(pname)
  
  if __name__ == '__main__':
    p_manag_num = 2 # 进程并发控制数量2
    # 并发的进程名
    q_process = ['process_1','process_2','process_3','process_4','process_5']
    q_a = Queue() # 将进程名放入队列
    q_b = Queue() # 将q_a的进程名放往q_b进程,由子进程完成
  
    for i in q_process:
      q_a.put(i)
  
    p_list = [] # 完成的进程队列
    while not q_a.empty():
      if len(p_list) <= 2:
        pname=q_a.get()
        p = Process(target=work, args=(pname,q_b))
        p.start()
        p_list.append(p)
        print pname
  
      for p in p_list:
        if not p.is_alive():
          p_list.remove(p)
  
    # 等待5秒,预估执行完后看队列通信信息
    # 当然也可以循环判断队列里面的进程是否执行完成
    time.sleep(5)
    print '打印p_b队列:'
    while not q_b.empty():
      print q_b.get()

执行结果:

python多进程控制学习小结

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

Python 相关文章推荐
Win7上搭建Cocos2d-x 3.1.1开发环境
Jul 03 Python
python处理Excel xlrd的简单使用
Sep 12 Python
Python常见内置高效率函数用法示例
Jul 31 Python
Python之两种模式的生产者消费者模型详解
Oct 26 Python
python flask框架实现传数据到js的方法分析
Jun 11 Python
Python中字符串List按照长度排序
Jul 01 Python
Python中断多重循环的思路总结
Oct 04 Python
使用python无账号无限制获取企查查信息的实例代码
Apr 17 Python
Python 实现一个简单的web服务器
Jan 03 Python
python 三边测量定位的实现代码
Apr 22 Python
总结几个非常实用的Python库
Jun 26 Python
python3操作redis实现List列表实例
Aug 04 Python
在Python中实现替换字符串中的子串的示例
Oct 31 #Python
python创建文件时去掉非法字符的方法
Oct 31 #Python
python3 中文乱码与默认编码格式设定方法
Oct 31 #Python
解决python中 f.write写入中文出错的问题
Oct 31 #Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
Oct 30 #Python
python将txt文件读入为np.array的方法
Oct 30 #Python
Python 将Matrix、Dict保存到文件的方法
Oct 30 #Python
You might like
VFP与其他应用程序的集成
2006/10/09 PHP
一个数据采集类
2007/02/14 PHP
dedecms中常见问题修改方法总结
2007/03/21 PHP
php smarty截取中文字符乱码问题?gb2312/utf-8
2011/11/07 PHP
php中XMLHttpRequest(Ajax)不能设置自定义的Referer的解决方法
2011/11/26 PHP
如何利用PHP执行.SQL文件
2013/07/05 PHP
学习php设计模式 php实现合成模式(composite)
2015/12/08 PHP
Zend Framework基于Command命令行建立ZF项目的方法
2017/02/18 PHP
在IE6下发生Internet Explorer cannot open the Internet site错误
2010/06/21 Javascript
基于JQuery的浮动DIV显示提示信息并自动隐藏
2011/02/11 Javascript
JS实现匀速运动的代码实例
2013/11/29 Javascript
Js与下拉列表处理问题解决
2014/02/13 Javascript
javascript页面渲染速度测试脚本分享
2014/04/15 Javascript
JavaScript判断变量是对象还是数组的方法
2014/08/28 Javascript
浅谈EasyUI中Treegrid节点的删除
2015/03/01 Javascript
JavaScript表单验证的两种实现方法
2017/02/11 Javascript
JavaScript脚本语言是什么_动力节点Java学院整理
2017/06/26 Javascript
快速搭建React的环境步骤详解
2017/11/06 Javascript
详解.vue文件解析的实现
2018/06/11 Javascript
利用chrome浏览器进行js调试并找出元素绑定的点击事件详解
2021/01/30 Javascript
Node.js 实现远程桌面监控的方法步骤
2019/07/02 Javascript
vue实现页面滚动到底部刷新
2019/08/16 Javascript
uni-app 支持多端第三方地图定位的方法
2020/01/03 Javascript
python代码制作configure文件示例
2014/07/28 Python
Python 不同对象比较大小示例探讨
2014/08/21 Python
python的移位操作实现详解
2019/08/21 Python
HTML5调用手机发短信和打电话功能
2020/04/29 HTML / CSS
do you have any Best Practice for testing
2016/06/04 面试题
教师实习的自我鉴定
2013/10/26 职场文书
企业授权委托书范本
2014/04/02 职场文书
加入学生会演讲稿
2014/04/24 职场文书
三八活动策划方案
2014/08/17 职场文书
终止合同协议书范本
2016/03/22 职场文书
nginx 多个location转发任意请求或访问静态资源文件的实现
2021/03/31 Servers
Redis实现主从复制方式(Master&Slave)
2022/06/21 Redis
详解Spring Security如何在权限中使用通配符
2022/06/28 Java/Android