守护进程进程安全

1.守护进程
  指的也是一个进程,可以守护着另一个进程
    一个进程a设置为b的守护进程 当b结束时 a会立马结束自己不管任务是否执行完毕
  使用场景:例如qq进程 有一个下载任务 交给了一个子进程
    但是过程中 qq退出了 下载进程也会随之关闭了

import time
from multiprocessing import Process


def task():
print('妃子的一生。。。')
time.sleep(10)
print('妃子挂了。。。')


if __name__ == '__main__':
print('皇帝登基!')
p = Process(target=task)
# 将p子进程设置为主进程的守护进程 必须放在开启进程之前设置
p.daemon = True
print('有一个妃子', p)
p.start()
time.sleep(5)
print('皇帝驾崩了。。。')
守护线程

2.进程安全
进程安全问题:
  当多个进程要同时操作同一个资源时,就可能出现问题
例如:
  只有一台打印机 但是很多打印任务 如果不加以控制 可能造成打印结果错乱
解决方案1:加join 将原本的并发的任务变成串行执行
  但是如此一来 进程与进程之间不再平等 顺序已经固定死了
  最终的解决方案就是加锁
  使用Lock来实例化产生一把锁
  但是要保证每个进程访问的都是同一把锁
在访问共享资源前 加锁
  访问后一定要解锁
注意:不能多次执行acquire 一次acquire 对应一次release
  acquire时一个阻塞函数 会一直等到锁被释放(release调用)才会继续执行
  加锁之后并发又变成了串行了 不过与join不同的是 没有规定顺序 谁先抢到谁先执行
  问题:一旦加锁 效率降低 不加锁数据要错乱

from multiprocessing import Process, Lock
import time
import random


def task1(lock):
lock.acquire()
print('hello my name is aaa')
time.sleep(random.randint(1, 3))
print('sjh age is 18')
time.sleep(random.randint(1, 3))
print('sjh sex is man')
lock.release()


def task2(lock):
lock.acquire()
print('hello my name is yy')
time.sleep(random.randint(1, 3))
print('yy age is 18')
time.sleep(random.randint(1, 3))
print('yy sex is woman')
lock.release()


def task3(lock):
lock.acquire()
print('hello my name is my')
time.sleep(random.randint(1, 3))
print('my age is 18')
time.sleep(random.randint(1, 3))
print('my sex is woman')
lock.release()


if __name__ == '__main__':
lock = Lock()
p1 = Process(target=task1, args=(lock,))
p2 = Process(target=task2, args=(lock,))
p3 = Process(target=task3, args=(lock,))
p1.start()
# p1.join()
p2.start()
# p2.join()
p3.start()

# p3.join()

print('over')
线程锁

互斥锁
  互相排斥对方的锁
  a在执行b就滚一边去
  在使用锁的时候 无可避免的会降低效率
  需要找到一个最合适的地方加上锁
  你锁住的代码越少效率越高
  join和锁
    join是让整个进程中的代码全部串行 而锁可以让部分代码串行
    粒度(被锁住的代码量)越小 效率越高
  抢票案例
    服务器器要存储票数
    客户端要查看票数
    如果票数大于0就可以购买

#其中的'data.json'为 {"ticket": 2}
import json, time, random, os
from multiprocessing import Process, Lock


def task(lock, name):
# 查看余票
check_ticket(name)
# 买票会修改数据 必须加锁
lock.acquire()
buy_ticket(name)
lock.release()


def check_ticket(name):
with open('data.json', 'rt', encoding='utf-8') as f:
ticket = json.load(f)['ticket']
print('%s查看了票数 剩余票数:%s' % (name, ticket))


def buy_ticket(name):
# 先查询是否有票
# time.sleep(random.randint(1, 4))
with open('data.json', 'rt', encoding='utf-8')as f:
ticket_dic = json.load(f)
if ticket_dic['ticket'] > 0:
# 买票 需要发送请求 模拟延迟
time.sleep(random.randint(1, 4))
ticket_dic['ticket'] -= 1
with open('data.json', 'wt', encoding='utf-8') as f1:
json.dump(ticket_dic, f1)
print('%s购买成功!' % name)
else:
print('没有票了!')


if __name__ == '__main__':
lock = Lock()
p1 = Process(target=task, args=(lock, 'apple'))
p2 = Process(target=task, args=(lock, 'lemon'))
p3 = Process(target=task, args=(lock, 'mango'))
p1.start()
# p1.join()
p2.start()
# p2.join()
p3.start()
抢票案例

3.IPC进程间通讯
  进程与进程之间内存是物理隔离的 无法直接通讯
  例如:qq要调用浏览器 来显示某个网页 网页地址就必须想办法告诉浏览器
四种方式:
  1.使用一个共享文件 在硬盘创建一个文件 不同进程之间共享这个文件
    优点:交换的数据量几乎没有限制
    缺点:速度慢
  2.系统开辟一块共享内存 以供进程间交换数据
    优点:速度快
    缺点:数据量不能太大
  3.管道
    优点:封装了文件的打开 关闭等操作
    缺点:速度慢 并且是单向的 编程复杂度高
  4.socket
    不仅可以用于与远程计算机中的进程通讯 还可以用于与本地进程通讯
    基于内存的 速度快

from multiprocessing import Process, Manager, Lock
import time


def task(dic, lock):
lock.acquire()
i = dic['num']
time.sleep(0.3)
dic['num'] = i - 1
lock.release()
pass


if __name__ == '__main__':
# 共享内存管理器
m = Manager()
# 在共享内存区域 创建了一个字典
# dic = m.dict({'name': 'sjh'})
dic = m.dict({'num': 10})
lock = Lock()
a = 100
p1 = Process(target=task, args=(dic, lock))
p2 = Process(target=task, args=(dic, lock))
p3 = Process(target=task, args=(dic, lock))
p1.start()

p2.start()
p1.join()
p2.join()
print(dic['num'])
进程锁

manager
queue
  队列也是一个容器
    特点:先进先出
    支持进程间共享
    自动处理了进程安全问题(加锁)
    例如:迅雷下载 先添加的任务一定先开始执行
  堆栈:
    特点:先进后出
    例如:函数的执行

from multiprocessing import Queue

q = Queue(2)
q.put('1')
q.put('2')
# print(q.get())
# q.put('3') # 会阻塞直到有空位置为止
# print(q.get())
# print(q.get())
# print(q.get()) # 会阻塞直到有数据为止
# # block阻塞
# timeout等待超时 只在block为True时有效
q.put('3', block=True, timeout=5)


queue的使用
from multiprocessing import Process, Queue
import time


def task(q):
num = q.get()
# print(num)
time.sleep(0.5)
q.put(num - 1)


if __name__ == '__main__':
q = Queue()
q.put(3)
# 将处于共享内存区域的字典传给子进程
p1 = Process(target=task, args=(q,))
p2 = Process(target=task, args=(q,))
p3 = Process(target=task, args=(q,))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()

print(q.get())
Queue

4.生产者消费者模型
  需求:一共要生产 并消费10台手机
  由于 生产者和消费者能力不匹配(处理速度不一致)导致双方可能互相等待 造成了效率的降低
  1.将原本由一个进程完成的 两个(生成和消费)拆分为两个不交给两个不同的角色(进程)来完成
  2.由于进程间内存互相隔离 所以需要为两个角色之间提供一个共享的数据容器
  3.生产将生产完成的数据放入容器中
  4.消费者从容器中取出数据来处理
    生产者消费者模型的优点:
      1.平衡了生产者和消费者的能力差异 提高处理效率
      2.降低了双方耦合度
  学习并发的两个核心问题 安全性和效率

from multiprocessing import Process, Queue

import time, random


# 生产者
def xiaomi_factory(name, q):
for i in range(1, 6):
time.sleep(random.randint(1, 3))
phone = '这是%s生产的小米9-%s' % (name, i)
print('生产者 生产了%s' % phone)
# 放到柜台即存储到队列中
q.put(phone)


# 消费者
def buy_mi9(q):
for i in range(10):
# 从队列中取需要被处理的数据(phone)
time.sleep(random.randint(1, 2))
phone = q.get()
print('消费者 消费了%s' % phone)


if __name__ == '__main__':
# 共享数据的队列
q = Queue()
# 生产者
p1 = Process(target=xiaomi_factory, args=('北京公司', q))
p2 = Process(target=xiaomi_factory, args=('上海公司', q))
p1.start()
p2.start()
# 消费者
c1 = Process(target=buy_mi9, args=(q,))
c1.start()
生产者消费者模型

转载于:https://www.cnblogs.com/ShenJunHui6/p/10485198.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值