python实现多进程代码示例

yipeiwu_com6年前Python基础

想要充分利用多核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中subprocess批量执行linux命令

可以执行shell命令的相关模块和函数有: os.system os.spawn os.popen --废弃 popen --废弃 commands --废弃,3....

Python实现网页截图(PyQT5)过程解析

方案说明 功能要求:实现网页加载后将页面截取成长图片 涉及模块:PyQT5 PIL 逻辑说明: 1:完成窗口设置,利用PyQT5 QWebEngineView加载网页地址,待网页加...

python利用正则表达式搜索单词示例代码

前言 在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配。正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行。 比如下面的例子,就是用来从一段文字...

pandas 实现将重复表格去重,并重新转换为表格的方法

在python处理数据时,经常用到DataFrame和set。 train=pd.read_csv('XXX.csv')#读取文件 train=train['item_id']#选...

python3之模块psutil系统性能信息使用

psutil是个跨平台库,能够轻松实现获取系统运行的进程和系统利用率,包括CPU、内存、磁盘、网络等信息。 它主要应用于信息监控,分析和限制系统资源及进程的管理。它实现了同等命令命令行工...