zoukankan      html  css  js  c++  java
  • 守护进程进程安全

    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()
    生产者消费者模型
  • 相关阅读:
    知识小罐头05(tomcat8请求源码分析 上)
    知识小罐头04(idea+maven+部署war包到tomcat 下)
    知识小罐头03(idea+maven+部署war包到tomcat 上)
    带着新人学springboot的应用13(springboot+热部署)
    带着新人学springboot的应用12(springboot+Dubbo+Zookeeper 下)
    带着新人学springboot的应用11(springboot+Dubbo+Zookeeper 上)
    带着新人学springboot的应用10(springboot+定时任务+发邮件)
    带着新人学springboot的应用09(springboot+异步任务)
    带着新人学springboot的应用08(springboot+jpa的整合)
    windows最简单的局部截图工具
  • 原文地址:https://www.cnblogs.com/ShenJunHui6/p/10485198.html
Copyright © 2011-2022 走看看