python中的多进程、进程池和进程间通信

多进程

        multiprocessing.Process

        创建进程的类:Process([group [, target [, name [, args [, kwargs]]]]]),target表示调用对象,args表示调用对象的位置参数元组。kwargs表示调用对象的字典。name为别名。group实质上不使用。
方法:is_alive()、join([timeout])、run()、start()、terminate()。其中,Process以start()启动某个进程。

属性:authkey、daemon(要通过start()设置)、exitcode(进程在运行时为None、如果为–N,表示被信号N结束)、name、pid。其中daemon是父进程终止后自动终止,且自己不能产生新进程,必须在start()之前设置。

        创建的多个进程是一块执行的

from multiprocessing import Process
import time
import os

def func(str):
    print("Process:",str," Pid:", os.getpid())
    time.sleep(3)
    print("Process:",str, "end"," Pid:", os.getpid())

if __name__ == '__main__':
     t1 = time.time()
     # 子进程异步,多个进程一起执行
    p1 = Process(target=func,args=("apply 0",))
    p2 = Process(target=func,args=("apply 1",))
    p3 = Process(target=func,args=("apply 2",))
    p4 = Process(target=func,args=("apply 3",))
    p5 = Process(target=func,args=("apply 4",))
    p1.start()
    p2.start()
    p3.start()
    p4.start()
    p5.start()

    print("Main End")
    print(time.time() - t1)
进程池

        multiprocessing.Pool

        开多进程是为了并发,通常有几个cpu核心就开几个进程,但是进程开多了会影响效率,主要体现在切换的开销,所以引入进程池限制进程的数量。

        进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

from multiprocessing import Pool, Process
import time
import os

def func(str):
    print("Pool:",str," Pid:", os.getpid())
    time.sleep(3)
    print("Pool:",str, "end"," Pid:", os.getpid())

if __name__ == '__main__':
    p = Pool(3)

    t1 = time.time()
    # for i in range(4):
    #     msg = "apply %d"%(i)
        # 这里其实类似一个单进程过程,一般情况
        # p.apply(func, (msg,))

    # apply同步,子进程一个一个执行
    # p.apply(func,("apply 0",))
    # p.apply(func,("apply 1",))
    # p.apply(func,("apply 2",))
    # p.apply(func,("apply 3",))
    # p.apply(func,("apply 4",))

    # apply_async异步,多个子进程一起执行
    # p.apply_async(func, ("apply 0",))
    # p.apply_async(func, ("apply 1",))
    # p.apply_async(func, ("apply 2",))
    # p.apply_async(func, ("apply 3",))
    # p.apply_async(func, ("apply 4",))

    p.close()
    p.join()
    print("Main End")
    print(time.time() - t1)
进程间通信

        一、队列 :multiprocessing.Queue

        不同于线程queue,进程queue的生成是用multiprocessing模块生成的。

        在生成子进程的时候,会将代码拷贝到子进程中执行一遍,及子进程拥有和主进程内容一样的不同名称空间

        示例如下:

①主进程和子进程各自拥有的不是同一个队列,之间不能通信

import multiprocessing
def foo():
    q.put([11,'hello',True])
    print(q.qsize())

q=multiprocessing.Queue() #全局定义一个q进程队列,在产生子进程时候会在子进程里生成,可以指定最大数,限制队列长度
if __name__ == '__main__':
    p=multiprocessing.Process(target=foo,args=()) #因为名称空间不同,子进程的主线程创建的q队列,主进程get不到,所以会阻塞住
    p.start()
    # foo() #主进程执行一下函数就可以访问到了
    print(q.get())

②主进程创建了队列,子进程报错,找不到队列q

import multiprocessing

def foo():
    q.put([15,'hello',{"a":"b"}])
    print(q.qsize())


if __name__ == '__main__':
    q = multiprocessing.Queue() #主进程创建一个q进程队列,子进程不会执行该语句
    p=multiprocessing.Process(target=foo,args=()) #因为名称空间不同,子进程的主线程找不到q队列,所以会报错提示没有q
    p.start()
    print(q.get())
    # 程序报错,子进程找不到q队列

③主进程创建队列,并作为参数传递给子进程,从而进程间可以通信

import multiprocessing
import os

def foo(argument):
    print('子进程', os.getpid())#定义函数处理进程队列
    print("父进程",os.getppid())
    argument.put([15,'hello',{"a":"b"}])
    print(argument.qsize())
q = multiprocessing.Queue() #全局定义一个进程队列,主进程和子进程在运行时都会分别创建一个q队列,但是创建的队列是不同的
print('test', os.getpid())  #主进程和子进程都会运行该语句

if __name__ == '__main__':
    x = multiprocessing.Queue()   #主进程定义一个进程队列
    p=multiprocessing.Process(target=foo,args=(x,))     #主进程把值传给子进程就可以处理了
    p.start()
    p.join()
    print(x.get())

    foo(q)  #主进程创建q队列,并作为参数传递给foo
    print(q.get())#这是主进程调用的q
数据共享

        Queue和pipe只是实现了数据交互,并没实现数据共享,即一个进程去更改另一个进程的数据。
        注:进程间通信应该尽量避免使用共享数据的方式

        ①共享变量

import multiprocessing
import time
import random

# 存取
def deposit(n,lock):
    for i in range(10):
        time.sleep(random.randint(0,2))
        # 获取锁使用权限
        lock.acquire()
        # 尽量让加锁的粒度最小,不到不得不要轻易加锁
        n.value += i
        # 释放使用权限
        lock.release()

# 取钱
def withdraw(n,lock):
    for i in range(10):
        time.sleep(random.randint(0,2))
        lock.acquire()
        n.value -= i
        lock.release()

if __name__ == '__main__':
    # 使用系统创建的共享变量money它是integer(i), 值2000
    money = multiprocessing.Value('i', 2000)
    lock = multiprocessing.Lock()

    # 创建了两个进程,一个进程存钱,一个进程取钱
    d = multiprocessing.Process(target=deposit, 
        args=(money, lock))
    w = multiprocessing.Process(target=withdraw, 
        args=(money, lock))
    
    # 等待这两个进程执行逻辑,直到执行结束
    d.start()
    w.start()
    time.sleep(3)
    print(money.value)
    d.join()
    w.join()

    # 打印最终的结果,如果不是2000,说明银行系统存在漏洞
    print(money.value)        

        ②共享数组

import multiprocessing
from datetime import datetime, timedelta

def trans(a, size):
    #打印出访问这些数组的具体时间
    t = datetime.now()
    for i in range(size):
        print(a[i])
    print("消耗%s"%(datetime.now()-t))


if __name__ == '__main__':
    print("Test share Memory")

    # 建立起一个在两个进程之间共享的共享内存数组
    # 数组类型是整形,大小是10
    num = 10
    a = multiprocessing.Array('i', num)


    # 创建一个进程,把共享数组和长度传递给进程
    p = multiprocessing.Process(target=trans, 
                                args=(a,num))
    p.start()

        ③进程池中使用队列

from multiprocessing import Manager, Pool
import time

# Manager().Queue()与Pool一起用;
# multiprocessing.Queue()与Procssess一起用

# 这里的get_nowait,put_nowait和get, put应该是效果一样的,
#因为这个操作的过程太短
def read(q):
    for i in range(q.qsize()):
        print("read from manager queue:%s"%q.get_nowait())

def write(q):
    for i in "ABCDEFG":
        time.sleep(2)
        q.put_nowait(i)

if __name__ == '__main__':
        # Manager大神管理Pool中队列
        q = Manager().Queue()
        
        # 通过进程池创建两个进程,一个写,一个读
        p = Pool(2)
        p.apply_async(write,(q,))
        p.apply_async(write,(q,))

        p.apply_async(read,(q,))

        p.close()
        p.join()
        print("main end")

        ④共享数据:列表

from multiprocessing import Manager,Process
def foo(l,i):
    l.append(i**i)
if __name__ == '__main__':
    man=Manager()
    ml=man.list([11,22,33])
    l=[]
    for i in range(5):
        p=Process(target=foo,args=(ml,i))
        p.start()
        l.append(p)
    for i in l: #必须要join,不然会执行报错,处理一个数据必须要一个个来,不能同时处理一个数据
        i.join()
    print(ml)

        ⑤共享数据:字典

from multiprocessing import Manager,Process
def foo(d,k,v):
    d[k]=v
if __name__ == '__main__':
    man=Manager()
    md=man.dict({'name':'bob'})
    l=[]
    for i in range(5):
        p=Process(target=foo,args=(md,i,'a'))
        p.start()
        l.append(p)
    for i in l: #必须要join,不然会执行报错,处理一个数据必须要一个个来,不能同时处理一个数据
        i.join()
    print(md)
详情可参考: http://www.cnblogs.com/kaituorensheng/p/4445418.html


猜你喜欢

转载自blog.csdn.net/weixin_41601173/article/details/80725220