Python的多进程模块multiprocessing

Python09

Python的多进程模块multiprocessing,第1张

众所周知,Python中不存在真正的多线程,Python中的多线程是一个并发过程。如果想要并行的执行程序,充分的利用cpu资源(cpu核心),还是需要使用多进程解决的。其中multiprocessing模块应该是Python中最常用的多进程模块了。

基本上multiprocessing这个模块和threading这个模块用法是相同的,也是可以通过函数和类创建进程。

上述案例基本上就是笔者搬用了上篇文章多线程的案例,可见其使用的相似之处。导入multiprocessing后实例化Process就可以创建一个进程,参数的话也是和多线程一样,target放置进程执行函数,args存放该函数的参数。

使用类来创建进程也是需要先继承multiprocessing.Process并且实现其init方法。

Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求。

但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程。

需要注意的是,在调用join方法阻塞进程前,需要先调用close方法,,否则程序会出错。

在上述案例中,提到了非阻塞,当把创建进程的方法换为pool.apply(func, (msg,))时,就会阻塞进程,出现下面的状况。

在multiprocessing模块中还存在Queue对象,这是一个进程的安全队列,近似queue.Queue。队列一般也是需要配合多线程或者多进程使用。

下列案例是一个使用进程队列实现的生产者消费者模式。

multiprocessing支持两种进程间的通信,其中一种便是上述案例的队列,另一种则称作管道。在官方文档的描述中,multiprocessing中的队列是基于管道实现的,并且拥有更高的读写效率。

管道可以理解为进程间的通道,使用Pipe([duplex])创建,并返回一个元组(conn1,conn2)。如果duplex被置为True(默认值),那么该管道是双向的,如果duplex被置为False,那么该管道是单向的,即conn1只能用于接收消息,而conn2仅能用于发送消息。

其中conn1、conn2表示管道两端的连接对象,每个连接对象都有send()和recv()方法。send和recv方法分别是发送和接受消息的方法。例如,可以调用conn1.send发送消息,conn1.recv接收消息。如果没有消息可接收,recv方法会一直阻塞。如果管道已经被关闭,那么recv方法会抛出EOFError。

关于multiprocessing模块其实还有很多实用的类和方法,由于篇幅有限(懒),笔者就先写到这里。该模块其实用起来很像threading模块,像锁对象和守护线程(进程)等multiprocessing模块也是有的,使用方法也近乎相同。

如果想要更加详细的了解multiprocessing模块,请参考官方文档。

17.1 subprocess

这个模块允许你产生子线程,连接他们(主线成,和产生的子线程)之间的输入/输出/错误 管道(pipes,管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法)。这个模块想要替换一些比较旧的模块和方法:

17.1.1 使用subprocess

在使用subprocess时推荐调用以下几个方来完成你的需求。如果有更高级的情况,可以使用Popen接口。

根据args参数运行命令,等待命令执行结束,返回进程返回值

根据args参数运行命令,等待命令执行结束,如果进程返回值为0则返回(return),否则会raise一个CalledProcessError错误,CalledProcessError类的returncode属性会包含进程返回值。

subprocess.check_output( args , * , stdin=None , stderr=None , shell=False , universal_newlines=False )

正在更新....

管道调用子程序

我们想在程序中使用一个子程序,但是需要动态的传递参数(这里说的动态,是指根据上次子程序输入的结果来决定这次输入什么),怎么办呢,不用慌,有subprocess!

下文我先介绍一个例子代码,以及他的输出结果!

1.#!/usr/bin/python2.from subprocess import *3.# Subprocess management,可以做很多子进程的文件,我们要引入这个文件4.p = Popen(["cat", "-n"], bufsize=1024,stdin=PIPE, 5.stdout=PIPE, close_fds=True)6.# 打开程序第一个参数是一个列表(程序名称,参数)7.# 第二个参数是缓冲区大小8.# stdin,stdout是设置是否打开这些管道,如果他的值是subprocess.PIPE的话,9.# 就会打开,同stdin一样的还有stderr10.# close_fds设置为true(unix-only)所有的文件描述符除了(0,1,2)在子程序执行前都会关闭11.(fin, fout) = (p.stdin, p.stdout)12.for i in range(10): # 你会懂的^_^ 13.fin.write("line" + str(i)) 14.fin.write('\n') 15.fin.flush() 16.print fout.readline()

他的输出结果是:1.line02.line13.line24.line35.line46.line57.line68.line79.line810.line9