毛毛Python进阶之路4——信号量、事件、队列、生产者消费者模型、管道、进程池及其返回值!

毛毛Python进阶之路4——信号量、事件、队列、生产者消费者模型、管道、进程池及其返回值!

1、信号量

上次我们讲到了锁,可以控制某段程序在同一时间内只能被一个进程锁访问。现在我想被两个进程访问,或者更多怎么办了?信号量就由此而生!
在这里插入图片描述

这就是信号量做的事!这段程序我可以指定多少人来使用,后面想使用就得等其他的人用完了才可以用!具体代码实现如下!
代码方法 | 功能

from multiprocessing import Semaphore,Process
import time

def func(msg,sem):
    sem.acquire()
    time.sleep(2)
    print("我是子进程!", msg)
    print(time.ctime())
    sem.release()

if __name__ == '__main__':
    sem = Semaphore(3)
    for i in range(10):
        p = Process(target=func,args= (i,sem) )
        p.start()

在这里插入图片描述
通过时间截图可以看出没2秒执行了三个程序!值得注意的是 传参的时候不要忘了传递 “Sem”!

2、事件——通过一个信号来控制多个进程同时执行或阻塞!

1、一个信号可以使所有的进程进入阻塞。
2、也可以控制所有的进程解除阻塞。
3、一个事件创建之后,默认是阻塞状态。

在这里用到的是Event 函数!

from multiprocessing import Event

e = Event #创建一个事件
e.is_set() #查看一个事件的状态、默认被设置成阻塞
e.wait() #是依据 e.is_set()的值来决定是否阻塞。“False”表示阻塞,“TRUE”表示不阻塞
e.set() #将某个事件的状态改为True
e.clear() #将某个事件的状态改为False

# 红绿灯事件
import time
import random
from multiprocessing import Event,Process
def cars(e,i):
    if not e.is_set():
        print('car%i在等待'%i)
        e.wait()    # 阻塞 直到得到一个 事件状态变成 True 的信号
    print('\033[0;32;40mcar%i通过\033[0m' % i)

def light(e):
    while True:
        if e.is_set():
            e.clear()
            print('\033[31m红灯亮了\033[0m')
        else:
            e.set()
            print('\033[32m绿灯亮了\033[0m')
        time.sleep(2)

if __name__ == '__main__':
    e = Event()
    traffic = Process(target=light,args=(e,))
    traffic.start()
    for i in range(20):
        car = Process(target=cars, args=(e,i))
        car.start()
        time.sleep(random.random())

3、进程间通讯(IPC)

在这里进程间的通讯使我们经常用的——队列

#from nultiprocess import Queue
#q = Queue(5) #可以存放的位数!
#q.put(1) # 想q里面存放,不能多于设定位数
#q.get() # 向q李阿敏去除数据,没有数据了就阻塞
#q.empty() # 判断李阿敏是否还有数据,没有就返回True
#q.get_nowait() # 使用这个函数就不会造成get的阻塞而是直接报错!产生异常

#通过队列,就可以实现两个子进程之间的通讯了!

from multiprocessing import Queue,Process
def produce(q):
    q.put('hello')

def consume(q):
    print(q.get())

if __name__ == '__main__':
    q = Queue()
    p = Process(target=produce,args=(q,))
    p.start()
    c = Process(target=consume, args=(q,))
    c.start()

4、通道

在这里插入图片描述
上图是通道的大概模型,我们通过函数将数据从一段塞进去,从另一端取出来,所用的就是通道!
具体使用方法如下:

from multiprocessing import Pipe
conn1,conn2 = Pipe()
conn1.recv() #取数据
conn2.send() #送数据(没有前后顺序)
conn1,conn2 如果任务执行完了需要关闭通道口,从而产生异常EOFErrer

Pipe 可以造成数据不安全,多个取出者由于数据延迟可能取出同一数据,所以应该加锁来避免进程报错!(所以不建议用管道)

5、进程池(优点:效率高)

在这里插入图片描述
进程池:就是可以应许设置个数的进程执行!
方法如下:
在这里插入图片描述

import os
import time
from multiprocessing import Pool
def func(n):
    print('start func%s'%n,os.getpid())
    time.sleep(1)
    print('end func%s' % n,os.getpid())

if __name__ == '__main__':
    p = Pool(5)
    for i in range(10):
        p.apply_async(func,args=(i,))
    p.close()  # 结束进程池接收任务
    p.join()   # 感知进程池中的任务执行结束
# 回调函数
import os
from multiprocessing import Pool
def func1(n):
    print('in func1',os.getpid())
    return n*n

def func2(nn):
    print('in func2',os.getpid())
    print(nn)

if __name__ == '__main__':
    print('主进程 :',os.getpid())
    p = Pool(5)
    for i in range(10):
        p.apply_async(func1,args=(10,),callback=func2)
    p.close()
    p.join()

6、进程池知识点

#进程池
# cpu个数+1
# ret = map(func,iterable)
    # 异步 自带close和join
    # 所有结果的[]
# apply
    # 同步的:只有当func执行完之后,才会继续向下执行其他代码
    # ret = apply(func,args=())
    # 返回值就是func的return
# apply_async
    # 异步的:当func被注册进入一个进程之后,程序就继续向下执行
    # apply_async(func,args=())
    # 返回值 : apply_async返回的对象obj
    #          为了用户能从中获取func的返回值obj.get()
    # get会阻塞直到对应的func执行完毕拿到结果
    # 使用apply_async给进程池分配任务,
    # 需要先close后join来保持多进程和主进程代码的同步性

人生苦短,我学python!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值