守护进程、互斥锁、IPC机制、生产者消费者模型

强调p.join的作用

from multiprocessing import Process
import time,os

def task():
    print('%s is running'%os.getpid())
    time.sleep()
    print('%s is done'%os.getpid())
if __name__=='__main__':
    p=Process(target=task)
    p.start()    #仅仅只是只是向操作系统发送一个开启进程的信号
    p.join    #等到子进程p执行完毕后,将p占用操作系统的pid进行回收
    print(p.pid)
    print('主')

守护进程

1、守护进程 

        守护进程其实就是一个'子进程'
        守护==》伴随
        守护进程会伴随主进程的代码运行完毕后终止结束

2、为何用守护进程

        两个关键点:
            进程:
                当父进程需要将一个任务并发出去执行,需要将该任务放到一个子进程里
            守护:
                当该子进程的代码在父进程代码运行完毕后就没有存在的意义了,就应该将该子进程设置为守护进程,会在父进程代码结束后死掉

from multiprocessing import Process
import time,os
def task(name):
    print('%s is running'%name)
    time,sleep(3)
if __name__=='__main__':
  p1=Process(target=task,args('守护进程',))

p1=Process(target=task,args('子进程',))
p1.daemon=True    #一定要放到p.start()之前才能生效,效果就是不会将结果打印到输出终端上,但会执行
p1.start()
p2.start()
print('主')
结果:
主
正常的子进程 is running
'''此处等待3秒后结束'''

主进程代码运行完毕后,守护进程就会结束掉

from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':
    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    print("main-------")

# 结果:
    '''
    main-------
    456
    end456
    等待3秒后结束代码
    '''

互斥锁

互斥锁:可以将要执行任务的部分代码(只涉及到修改共享数据的代码)变成串行
join:将要执行任务的所有整体代码变成串行

from multiprocessing import Process,Lock
import json
import os
import time
import random

def check():
    time.sleep(1)    #模拟网络延迟
    with open('db.txt','rt',encoding='utf-8')as f:
        dic=json.load(f)
    print('%s 查看到剩余票数 [%s]'%s(os.getpid(),dic['count']))
def get():
    with open('db.txt','rt',encoding='utf-8')as f:
        dic=json.load(f)
    time.sleep(2)
    if dic['count']>0:
        #有票
        dic['count']-=1
        time sleep(random.randint(1,3))
        with open('db.txt','wt',encoding='utf-8')as f:
            json.dump(dic,f)
        print('%s 购票成功'%os.getpid())
    else:
        print('%s 没有余票' %os.getpid())

def task(mutex):
    #查票
    check()
    #购票
    mutex.acquire()    #互斥锁不能连续的acquire,必须是release以后才能重新acquire
    get()
    mutex.release()
    '''可以简写为
    with mute:
        get()
    '''


if __name__ == '__main__':
    mutex=Lock()    #当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突。
    for i in  range(10):
        p=Process(target=task,args=(mutex,))
        p.start()
        # p.join()    #如果加入Join将会是check()和get()依次的串行效果
结果:
19748 查看到剩余票数 [0]
10720 查看到剩余票数 [0]
16264 查看到剩余票数 [0]
8860 查看到剩余票数 [0]
25496 查看到剩余票数 [0]
1848 查看到剩余票数 [0]
1460 查看到剩余票数 [0]
6884 查看到剩余票数 [0]
20064 查看到剩余票数 [0]
19320 查看到剩余票数 [0]
'''以上为并发效果'''
'''以下为串行效果'''
19748 没有余票
10720 没有余票
16264 没有余票
8860 没有余票
25496 没有余票
1848 没有余票
1460 没有余票
6884 没有余票
20064 没有余票
19320 没有余票

IPC机制

IPC:进程间通信,有两种实现方式

1、pipe
2、queue:pipe+锁

from ultiprocessing import Queue
q=Queue(3)    #先进先出
'''
注意:
1、队列占用的内存空间
2、不应该往队列中放大数据,应该只存放数据量较小的消息
# 需要掌握的
'''
q.put('first')
q.put({'k':second})
q.put(['third',])
q.put(4)

print(q.get())
print(q.get())
print(q.get())
print(q.get())

# 结果:
'''
first
{'k': 'sencond'}
['third']
|    #卡在这一步的原因是卡在了第四个print中,因为队列只允许3个进出,而第四个永远不会进去也就得拿不到结果


q.put()有三个参数,第二个参数block是阻塞,第三个timeout是超出时间,block=True才可以和timeout连用.
block默认是True,当队列满了,就会阻塞住,如果在timeout的超时时间内没有取出一个让队列空间有空余,就会报错
block=False时,当队列满了,就会立马报错
 
q.get()有三个参数,第二个参数block是阻塞,第三个timeout是超出时间.
block默认是True,当队列取空了,就会阻塞住,如果在timeout的超时时间内没有新的元素添加到队列中,就会报错.
block=False时,当队列取空时,就会立马报错
'''
# 了解的:  
q=Queue(3) # 先进先出
q.put('first',block=True,timeout=3)
q.put({'k':'sencond'},block=True,timeout=3)
q.put(['third',],block=True,timeout=3)
print('===>')
#q.put(4,block=True,timeout=3)

print(q.get(block=True,timeout=3))
print(q.get(block=True,timeout=3))
print(q.get(block=True,timeout=3))
print(q.get(block=True,timeout=3))

# 结果:
'''
===>
first
{'k': 'sencond'}
['third']
Traceback (most recent call last):
  File "D:/PycharmProjects/SH_OldBoy_Python/day33/04 IPC机制.py", line 37, in <module>
    print(q.get(block=True,timeout=3))
  File "D:\Python36-32\lib\multiprocessing\queues.py", line 105, in get
    raise Empty
queue.Empty    #由于Queue(3)为3,当打开到第四个print时,由于开启了block=True,timeout=3,等待3秒后
出现队列空白错误
'''
q=Queue(3) # 先进先出
q.put('first',block=False,)
q.put({'k':'sencond'},block=False,)
q.put(['third',],block=False,)
print('===>')
# q.put(4,block=False,) # 队列满了直接抛出异常,不会阻塞

print(q.get(block=False))
print(q.get(block=False))
print(q.get(block=False))
print('get over')
print(q.get(block=False))
'''错误结果直接抛出'''
q=Queue(3) # 先进先出

q.put_nowait('first') # q.put('first',block=False,)
q.put_nowait(2)
q.put_nowait(3)
# q.put_nowait(4)

print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())

# 结果:
'''
Traceback (most recent call last):
first
  File "D:/PycharmProjects/SH_OldBoy_Python/day33/04 IPC机制.py", line 66, in <module>
2
    print(q.get_nowait())
3
  File "D:\Python36-32\lib\multiprocessing\queues.py", line 126, in get_nowait
    return self.get(False)
  File "D:\Python36-32\lib\multiprocessing\queues.py", line 107, in get
    raise Empty
queue.Empty
'''

生产者消费者模型

1.什么是生产者消费者模型

    生产者:比喻的是程序中负责产生数据的任务
    消费者:比喻的是程序中负责处理数据的业务
    生产者-》共享的介质(队列)《-消费者

2.为何用

    实现了生产者与消费者的解耦合,生产者可以不停地生产,消费者也可以不停地消费
    从而平衡了生产者的生产能力与消费者消费能力,提升了程序整体运行的效率

3.什么用?

    当我们的程序中存在明显的两类任务,一类负责产生数据,另外一类负责处理数据
    此时就应该考虑使用生产者消费者模型来提升程序的效率

from multiprocessing import Queue, Process
import time
import os
import random


def producer(q):
    for i in range(10):
        res = '包子%s' % i
        time.sleep(random.randint(1, 3))    #随机生成整形数字
        # 往队列里丢
        q.put(res)
        print('\033[45m%s 生产了 %s\033[0m' % (os.getpid(), res))
    q.put(None)    # 等循环完后抛出None值


def consumer(q):
    while True:
        # 从队列里取走
        res = q.get()
        if res is None: break    #接收到producer函数内返回的None值进行break
        time.sleep(random.randint(1, 3))
        print('\033[46m%s 吃了 %s\033[0m' % (os.getpid(), res))


if __name__ == '__main__':
    q = Queue()
    # 生产者们
    p1 = Process(target=producer, args=(q,))
    # 消费者们
    c1 = Process(target=consumer, args=(q,))

    p1.start()
    c1.start()

    print('主')
from multiprocessing import JoinableQueue, Process
import time
import os
import random

def producer(name, food, q):
    for i in range(3):
        res = '%s%s' % (food, i)
        time.sleep(random.randint(1, 3))
        # 往队列里丢
        q.put(res)
        print('\033[45m%s 生产了 %s\033[0m' % (name, res))
    # q.put(None)

def consumer(name, q):
    while True:
        # 从队列里取走
        res = q.get()
        if res is None: break
        time.sleep(random.randint(1, 3))
        print('\033[46m%s 吃了 %s\033[0m' % (name, res))
        q.task_done()

if __name__ == '__main__':
    q = JoinableQueue()  # 这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
    # 生产者们
    p1 = Process(target=producer, args=('egon', '包子', q,))
    p2 = Process(target=producer, args=('杨军', '泔水', q,))
    p3 = Process(target=producer, args=('猴老师', '翔', q,))
    # 消费者们
    c1 = Process(target=consumer, args=('Alex', q,))
    c2 = Process(target=consumer, args=('wupeiqidsb', q,))
    c1.daemon = True
    c2.daemon = True

    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

    p1.join()
    p2.join()
    p3.join()

    q.join()  # 等待队列被取干净
    # q.join() 结束意味着
    # 主进程的代码运行完毕--->(生产者运行完毕)+队列中的数据也被取干净了->消费者没有存在的意义

    # print('主')

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值