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 相关文章推荐
python3使用tkinter实现ui界面简单实例
Jan 10 Python
python中List的sort方法指南
Sep 01 Python
简单介绍利用TK在Python下进行GUI编程的教程
Apr 13 Python
在Python web中实现验证码图片代码分享
Nov 09 Python
Python 实现网页自动截图的示例讲解
May 17 Python
TensorFlow实现卷积神经网络
May 24 Python
Python 找到列表中满足某些条件的元素方法
Jun 26 Python
Python使用matplotlib实现基础绘图功能示例
Jul 03 Python
Python用于学习重要算法的模块pygorithm实例浅析
Aug 16 Python
python tkinter图形界面代码统计工具
Sep 18 Python
OpenCV哈里斯(Harris)角点检测的实现
Jan 15 Python
tensorflow2.0保存和恢复模型3种方法
Feb 03 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
图形数字验证代码
2006/10/09 PHP
再次研究下cache_lite
2007/02/14 PHP
PHP实例分享判断客户端是否使用代理服务器及其匿名级别
2014/06/04 PHP
php中执行系统命令的方法
2015/03/21 PHP
对PHP依赖注入的理解实例分析
2016/10/09 PHP
jQuery的强大选择器小结
2009/12/27 Javascript
jquery each的几种常用的使用方法示例
2014/01/21 Javascript
Javascript学习笔记之函数篇(五) : 构造函数
2014/11/23 Javascript
使用AngularJS处理单选框和复选框的简单方法
2015/06/19 Javascript
jQuery.each使用详解
2015/07/07 Javascript
详解JavaScript对Date对象的操作问题(生成一个倒数7天的数组)
2015/10/01 Javascript
JavaScript仿商城实现图片广告轮播实例代码
2016/02/06 Javascript
js实现动态创建的元素绑定事件
2016/07/19 Javascript
鼠标经过出现气泡框的简单实例
2017/03/17 Javascript
JS实现两周内自动登录功能
2017/03/23 Javascript
vue数据双向绑定的注意点
2017/06/23 Javascript
微信小程序 共用变量值的实现
2017/07/12 Javascript
Vue列表渲染的示例代码
2018/11/01 Javascript
Vue渲染过程浅析
2019/03/14 Javascript
微信小程序国际化探索实现(附源码地址)
2020/05/20 Javascript
浅析 Vue 3.0 的组装式 API(一)
2020/08/31 Javascript
详解Vue中的watch和computed
2020/11/09 Javascript
[04:15]DOTA2-DPC中国联赛 正赛 Ehome vs Aster 选手采访
2021/03/11 DOTA
Python实现统计代码行的方法分析
2017/07/12 Python
对Python中的@classmethod用法详解
2018/04/21 Python
解决pycharm无法调用pip安装的包问题
2018/05/18 Python
使用pandas将numpy中的数组数据保存到csv文件的方法
2018/06/14 Python
python 一个figure上显示多个图像的实例
2019/07/08 Python
Html5移动端弹幕动画实现示例代码
2018/08/27 HTML / CSS
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
POP文化和音乐灵感的时尚:Hot Topic
2019/06/19 全球购物
亚洲最大的运动鞋寄售店:KicksCrew
2020/11/26 全球购物
毕业生自我鉴定范文
2013/11/08 职场文书
教师的实习自我鉴定
2013/12/17 职场文书
招标保密承诺书
2015/01/20 职场文书
Python 匹配文本并在其上一行追加文本
2022/05/11 Python