目录

  • 进程创建
  • 进程间通信(Queue,Pipe,Manager)
  • 进程同步(同步锁)和进程池

 


 进程创建

  创建进程实现在python下的并发,同时调用多个cpu来操作线程

方法一:

from multiprocessing import Process
import time


def f(name):
    time.sleep(1)
    print('hello', name,time.ctime())

if __name__ == '__main__':
    p_list=[]
    for i in range(3): #开启三个进程,此时是使用3个cpu,每个cpu分别执行一个

        p = Process(target=f, args=('alvin',))
        p_list.append(p)
        p.start()

    for i in p_list:
        i.join()
    print('end')

方法二:通过继承 

from multiprocessing import Process
import time

class MyProcess(Process):

    # def __init__(self):
    #     super(MyProcess, self).__init__()
    #     #self.name = name

    def run(self):
        time.sleep(1)
        print ('hello', self.name,time.ctime()) #self.name是进程名


if __name__ == '__main__':
    p_list=[]


    for i in range(3):
        p = MyProcess()
        # p.daemon=True #设置为守护进程
        p.start()
        p_list.append(p)

    for p in p_list:
        p.join() #如果子进程没有执行完,主进程就卡在这里,不往下运行

    print('end')

#########################################
hello MyProcess-1 Sat May  4 15:42:00 2019
hello MyProcess-2 Sat May  4 15:42:00 2019
hello MyProcess-3 Sat May  4 15:42:00 2019
end

os.getppid()

os.getpid()

p.is_alive()

p.terminate()

进程间通信

  进程间通信与线程间通信不同,线程之间共享一块内存,简单的线程间通信只要设置全局变量或者同步对象event(具体看进程篇)就能做到。而进程在不同的两块内存之中。

方案一:使用进程队列来实现进程间通信

import time

import multiprocessing
def foo(q):
    time.sleep(1)
    print("son process",id(q))
    q.put(123) #在子进程中放入值
    q.put("chen")

if __name__ == '__main__':

    q=multiprocessing.Queue() #创建进程队列
    p=multiprocessing.Process(target=foo,args=(q,)) #在进程之间传递进程队列,作为全局变量
    p.start()

    print("main process",id(q))
    print(q.get()) #在主进程中拿出数据
    print(q.get())

方案二:使用双向管道来实现经常队列

from multiprocessing import Process, Pipe
def f(conn):
    conn.send([12, {"name":"chen"}, 'hello']) #子进程给主进程发送数据
    response=conn.recv() #子进程接收主进程发送的数据
    print("response",response)
    conn.close() #关闭管道


if __name__ == '__main__':

    parent_conn, child_conn = Pipe() #创建双向管道


    p = Process(target=f, args=(child_conn,))
    p.start()

    print(parent_conn.recv())   # 主进程接收子进程发送的数据prints "[42, None, 'hello']"
    parent_conn.send("儿子你好!") #主进程给子进程发送数据
    p.join()

 方案二:使用Manager实现进程间通信

  Pipe和Queue只是实现了进程间数据的交互,并没有实现进程间数据共享,即一个进程修改另一个进程的数据

  Manager支持的类型有list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array。

from multiprocessing import Process, Manager

def f(d, l,n):
    
    d[n] = '1'    #{0:"1"}
    d['2'] = 2    #{0:"1","2":2}
    l.append(n)   #[0,1,2,3,4,   0,1,2,3,4,5,6,7,8,9]

if __name__ == '__main__':

    with Manager() as manager: #with语法自动close()

        d = manager.dict()#通过manager得到一个字典对象
        l = manager.list(range(5))#通过manager得到一个列表对象

        p_list = []
        for i in range(10):
            p = Process(target=f, args=(d,l,i)) #将通过manager创建的对象最为参数传入子进程中
            p.start()
            p_list.append(p)

        for res in p_list:
            res.join()

        print(d)
        print(l)

注:进程间的通信是很耗费资源的,因为存在两块不同的内存之中,所以本质上是一个进程将数据拷贝到另一个进程,存在内存的消耗。

 

进程同步(同步锁)和进程池

  在进程与进程之间的数据不共用,但是进程与进程间也有同时使用的系统资源,比如终端和屏幕,在多个进程向显示器输出内容的时候,可能会导致数据混乱的显现,比如:

python 结束进程 multiprocessing python结束进程树_进程池

 因此使用进程同步锁来规定同一时刻,只能有一个进程来使用共用资源。

from multiprocessing import Process, Lock
import time

def f(lock, i):
    lock.acquire() #请求同步锁
    time.sleep(1)
    print('hello world ',i)
    lock.release() #释放同步锁

if __name__ == '__main__':
    lock = Lock() #创建同步锁

    for num in range(10):
        Process(target=f, args=(lock, num)).start()

进程池

  在内存中同时会有很多的进程需要执行,那改怎么去执行这些进程成了问题,如果去同时运行这些进程那就太耗费资源,但是一个一个执行就费时,因此引入进程池,使用一个折中 的办法,在进程池中指定最大执行进程数量,进程的完执行速度有快有慢,当进程池中的某个进程执行完,等待的进程就可以进入进程池执行,直到完成所有进程的执行。

#每一秒执行5个进程
from  multiprocessing import Pool
import time

def Foo(i):

    time.sleep(1)
    print(i)

    return "HELLO %s"%i

def Bar(arg):
    print(arg)
    print("hello")

if __name__ == '__main__':

    pool = Pool(5) #定义进程池的最大进程数。如果不指定数目,默认根据电脑的cpu数量
    for i in range(100): #开一百个子进程
        #开启进程池
        pool.apply_async(func=Foo, args=(i,),callback=Bar) #callback指定回调函数(就是某个动作或者函数执行成功后再去执行的函数)

    pool.close()
    pool.join()         # join与close调用顺序是固定的