多进程介绍
Python多线程无法利用CPU多核的优势。因此在Python开发中,我们一般使用多进程进行并行开发。multiprocessing是类似于threading模块的包。它支持了本地和远程并发性,可以更充分的利用多核资源。
Process类
要运行一个进程需要创建实例化一个Process对象并且调用该类的start()方法。
`
from multiprocessing import Process
def greet(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()`
Process([group [, target [, name [, args [, kwargs]]]]]),group默认为None,不使用,参数target为调用的对象,name为子进程的名字,args为调用对象的参数元组,kwargs为调用对象的字典。
有关的方法和属性
Process中的方法与threading.Thread中的十分相似。
run():进程启动时运行的方法。
start():启动进程,会调用子进程中的run()方法。
join([timeout]):主线程等待当前线程终止,timeout为可选的超时时间,join只能join住start开启的进程,而不能join住run开启的进程。
terminate():强制终止进程,不会进行任何清理操作,如果创建了子进程,该子进程就成了僵尸进程。如果进程还保存了一个锁那么也将不会被释放,进而导致死锁。
is_alive():判断进程是否在运行,为bool值。
name:进程的名字,它是string类型,没有语义,只是用于标志进程,多进程中允许使用同一个名字。
dameon:必须在start()调用前设置,默认为false,如果设为True,代表当前进程为后台运行的守护进程,当前进程的父进程终止时,它也随之终止,并且设定为True后,不能创建自己的新进程。
pid:进程的id
每个进程还有特有的id号,可以通过os.getpid()得到当前进程的ID号,也可以直接使用p.pid得到ID。
from multiprocessing import Process
import os
def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid())#得到父进程的id号
print('process id:', os.getpid())#得到当前进程的id号
def greet(name):
info('function greet')
print('hello', name)
if __name__ == '__main__':
info('main Process')
p = Process(target=greet, args=('bob',))
p.start()
p.join()
进程间的通信
多进程支持两种进程间通信的方式:队列和管道。
队列
队列具有先进先出的特点,并且它是线程和进程安全的,通过q.put()方法将数据插入到队列中,然后使用q.get()方法将数据取出。
from multiprocessing import Process, Queue
def greet(q):
q.put("hello")
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # 打印hello
p.join()
管道
Pipe()函数返回一对双向的连接对象,它们代表管道的两端。每个连接对象有send()和recv()方法。当两个进程或者线程试图同时写入或读取管道的一端时,管道中的数据会被损坏,当然同一时刻使用不同的管道端口不会有损坏的风险。
from multiprocessing import Process, Pipe
def greet(p):
p.send("hello")
p.close()
if __name__=='__main__':
left_p,right_p=Pipe()
p=Process(target=greet,args=(right_p,))
p.start()
print(left_p.recv()) #输出hello
p.join()
进程间的同步
多进程包含与多线程中等价的同步原语。例如可以使用锁机制确保某一时刻只有一个进程打印到标准输出。
from multiprocessing import Process, Lock
def greet(lock,num):
lock.acquire() #获取锁
print("hello",num)
lock.release() #将锁释放
if __name__=='__main__':
lock=Lock()
for num in range(5):
Process(target=greet,args=(lock,num),).start()
进程间分享状态
在进行并发编程时,最好尽量避免使用共享状态,尤其是使用多进程时。但是,如果你确实要使用一些共享的数据,多进程也提供一些方法。
共享内存
数组可以利用Value和Array存储在共享内存映射中。
from multiprocessing import Process, Value, Array
def share(val,arr):
val.value=1
for i in range(len(arr)):
arr[i]=arr[i]+1
if __name__=='__main__':
val=Value('d',0.0)
arr=Array('i',range(10))
p=Process(target=share,args=(val,arr))
p.start()
p.join()
print(val.value)
print(arr[:])
输出值为:
`1.0
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
`
其中d和i分别代表创建Value和Array中存储的数字类型为double和signed integer。这些共享对象都是线程和进程安全的。
服务器进程
通过Manager()创建一个管理类,它可以控制一个服务器进程,这些服务器进程持有Python对象,并且允许其他进程利用代理来操纵Python对象。
from multiprocessing import Process, Manager
def func(dic,li):
dic['hello']=1
dic[1]='Bob'
dic[2.01]=None
li.reverse()
if __name__=='__main__':
manager=Manager()
dic=manager.dict()
li=manager.list(range(5))
p=Process(target=func,args=(dic,li))
p.start()
p.join()
print(dic)
print(li)
输出结果为:
{'hello': 1, 1: 'Bob', 2.01: None}
[4, 3, 2, 1, 0]
服务器进程管理比使用共享内存对象更加的灵活,因为它可以支持任意类型的对象。manager也可以通过进程进行共享,只不过比使用共享内存慢。
进程池
进程池中有许多进程,它有方法让进程池中的进程以不同的方式运行任务。 可以创建一个池池,这些进程将执行池类向它提交的任务。
多进程编程并不是进程越多越好,还与CPU核数有关,进程数过多反而会降低效率。
Pool([processes[, initializer[, initargs[, maxtasksperchild]]]])
相关方法
apply(func[, args[, kwds]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用
p.apply_async()
apply_async(func [, args [, kwargs]]):在一个池工作进程中执func(*args,**kwargs),然后返回结果。此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。
close():关闭进程池。如果所有操作持续挂起,它们将在工作进程终止前完成。
P.join():等待所有工作进程退出。此方法只能在close()或teminate()之后调用
from multiprocessing import Pool
def sqr(x):
return x*x
if __name__=='__main__':
pool=Pool(processes=5) #开启5个工作进程
result=pool.apply_async(sqr,[10]) #异步计算sqr(10))
print(result.get(timeout=1)) #输出100
print(pool.map(sqr,range(5))) #输出[0,1,4.....16]
参考
https://www.cnblogs.com/smallmars/p/7093603.html
http://docspy3zh.readthedocs.io/en/latest/library/multiprocessing.html