Python多进程

多进程介绍

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

你可能感兴趣的:(Python基础)