其他关于Python的总结文章请访问:https://www.jianshu.com/nb/47435944
详解Python中的多进程、进程间通信(队列和管道) - multiprocessing、Process、Pool、Queue、Pipe详解
计算机执行任务都是多任务同步执行的,比如使用浏览器浏览网页是一个任务,同时使用编辑器写代码又是一个任务,计算机还有好多的后台任务,这些任务都是同时进行的。对于多核CUP来说,不同的任务可以被调度到多个核上平行进行,但是一个核上也同时进行着多个任务,在同一个核上的多个任务实机上是交替进行的,比如计算机使用0.0001秒执行一个任务,然后切换到另一个任务执行0.0001秒,如此交替运行多个任务,但是由于运算速度很快,所以让我们觉得这些任务是同时进行的。我们可以乘这些任务为进程(process
)。一个任务其实通常还有多个子任务同时进行,这些子任务被称之为线程(thread
),一个进程必定至少包括一个进程,也可以有多个线程,Python中可以使用多进程、多线程、多进程同时多线程等方式处理并行程序。
首先,每一个进程都可以使用 os.getpid()
的方法获取此进程的pid(要引入os
模块),pid是进程的唯一性标识。
Python中可以使用 multiprocessing
包来处理多进程:
import multiprocessing
使用Process处理多进程
使用 Process
可以创建一个进程,Process
创建进程时可以传入参数,target
参数接收一个函数作为该进程要执行的内容(函数可以带参数),然后使用args
参数为作为target
的函数传入参数,使用元组传入,最后要留有一个逗号。
一个Process
的实例有如下的一些方法:
-
start
: 开始该进程 -
join
:等待进程结束 -
terminate
:强制结束该进程
一个例子:
from multiprocessing import Process
import os
def print_process(text):
print("Process \n\tPID: {}\n\tTEXT: {}\n".format(os.getpid(), text))
if __name__ == "__main__":
print("Processes Starting...")
process1 = Process(target=print_process, args=('process 1',))
process2 = Process(target=print_process('process 2'))
process1.start()
process2.start()
process1.join()
process2.terminate()
print("Processes Ended")
得到的结果:
Processes Starting...
Process
PID: 17152
TEXT: process 2
Process
PID: 16884
TEXT: process 1
Processes Ended
使用Pool处理多进程
Pool
可以用于处理大量分进程,批量管理,实例化一个Pool
对象可以传入整数指定Pool
中最大同时执行的进程数量,默认值为你计算机CPU的核数。如果传入的参数大于计算机的核数,也就是默认值,则需要先跑完核数个进程后才会继续执行后边的进程(比如计算机核数为8,传入9作为参数,则会先执行8个进程,有一个进程执行结束后,才会有第九个进程开始执行)
一个Pool
实例的常用方法有:
-
apply_async
:向进程池中添加一个进程并设置要执行的内容,可以传入一个函数做参数,然后使用args
指定函数的参数,或者直接将参数写在函数后边,同理于Process
的参数 -
close
:关闭池,表示不会再给该进程池中添加新的进程 -
join
:等待池中所有进程结束
一个例子:
from multiprocessing import Pool
import os
def print_process(text):
print("Process \n\tPID: {}\n\tTEXT: {}".format(os.getpid(), text))
if __name__ == "__main__":
print("Processes Pool Starting...")
pool = Pool(2)
for i in range(3):
pool.apply_async(print_process(i + 1))
print("All processes have been added into the pool")
pool.close()
pool.join()
print("All processes in the pool have ended")
得到的结果:
Processes Pool Starting...
Process
PID: 17544
TEXT: 1
Process
PID: 17544
TEXT: 2
Process
PID: 17544
TEXT: 3
All processes have been added into the pool
All processes in the pool have ended
进程间通信
进程之间进行通信依赖于操作系统提供的多种机制,这里主要详述Python中常使用的两种机制:Queue
和Pipes
,它们的区别在于:
-
Queue
:队列,是先进先出的数据结构,可以供给多个写入者和多个读取者,写入者向队列的队尾写入数据,读取者从队列的队头读取数据 -
Pipes
:管道,只供给于一对进程通信,两个进程在管道的两端,两个进程都可以发送给对方消息以及接受对方的消息,管道可以理解为一根网线
使用Queue通信
使用Queue
创建一个队列实例,一个实例的主要方法:
-
put
:向队列的队尾写入数据 -
get
:从队列的队头读取数据
直接看一个例子,这个例子中我们定义两个进程,一个用来向队列中写入数据,一个用于从队列中读取数据:
from multiprocessing import Process, Queue
import os, time, random
def writer(queue):
print("Writing process with PID {}".format(os.getpid()))
for i in range(5):
print("Putting {} into the queue".format(i + 1))
queue.put(i + 1)
time.sleep(random.random())
def reader(queue):
print("Reading process with PID {}".format(os.getpid()))
while True:
get_value = queue.get()
print("Getting {} from the queue".format(get_value))
if __name__ == "__main__":
queue = Queue()
writer_process = Process(target=writer(queue))
reader_process = Process(target=reader(queue))
reader_process.start()
writer_process.start()
writer_process.join()
reader_process.terminate() # while True, 因此不能等到其结束,只能使用terminate
使用Pipes通信
使用Pipes
创建一个管道实例,一个管道实例的主要方法:
-
send
:向管道中发送信息 -
recv
:从管道中接收信息 -
close
:关闭管道
直接看一个例子,管道两端的进程互相给对方发消息:
from multiprocessing import Pipe
if __name__ == "__main__":
(pipe_left, pipe_right) = Pipe()
pipe_left.send("Hello, I'm LEFT!")
pipe_right.send("Hello, I'm RIGHT!")
print("pipe_left received {}".format(pipe_left.recv()))
print("pipe_right received {}".format(pipe_right.recv()))
pipe_left.close()
pipe_right.close()
得到的结果为:
pipe_left received Hello, I'm RIGHT!
pipe_right received Hello, I'm LEFT!