• day 35 GIL全局解释器 多线程和多进程 死锁和递归 协程


    今日内容:

    二、内容:

    1、生产者消费者模型补充

    from multiprocessing import Process,Queue
    import time,random,os
    
    def producer(name,food,q):
        for i in range(3):
            res="%s%s"%(food,i)
            time.sleep(0.5)
            q.put(res)
            print("%s 生产了%s"%(name,res))
    
    def consumer(name,q):
        while True:
            res=q.get()
            if res is None:
               break
            print("%s 吃 %s"%(name,res))
            time.sleep(random.randint(2,3))
    if __name__=="__main__":
        q=Queue()
        p1=Process(target=producer,args=("egon1","包子1",q,))
        p2=Process(target=producer,args=("egon2","包子2",q,))
        p3=Process(target=producer,args=("egon3","包子3",q,))
        c1=Process(target=producer,args=("alex",q,))
        c2=Process(target=producer,args=("wxx",q,))
    
        p1.start()
        p2.start()
        p3.start()
        c1.start()
        c2.start()
    
        p1.join()
        p2.join()
        p3.join()
        q.put(None)
        q.put(None)
        print("")
    生产者消费者比较LOW 的写法

    查看python进程

    利用守护进程来实现  生产者和消费者模型

    from multiprocessing import Process,Queue,JoinableQueue
    import time,random,os
    
    def producer(food,q):
        for i in range(3):
            res="%s%s"%(food,i)
            time.sleep(0.5)
            q.put(res)
            print("%s 生产了 %s"%(os.getpid(),res))
        q.join()
    
    def consumer(q):
        while True:
            res=q.get()
            print("%s 吃 %s"%(os.getpid(),res))
            time.sleep(random.randint(2,3))
            q.task_done()
    
    if __name__=="__main__":
        q=JoinableQueue()
        p1=Process(target=producer,args=("包子",q,))
        p2=Process(target=producer,args=("烤鸡",q,))
        p3=Process(target=producer,args=("gouliang",q,))
        c1=Process(target=consumer,args=(q,))
        c2=Process(target=consumer,args=(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()--->消费者确实把所有的数据都收到
        print('', os.getpid())
    生产者和消费者模型 新

    2、GIL解释器锁(就是一把互斥锁)

     (1)互斥锁就是为了保护数据

    (2)Cpython解释器中,统一进程下来气的多线程,统一时刻只能有一个线程执行,无法使用多核优势

    (3)8个线程可以被8个cpu执行,可以有两个进程,每个进程里面有四个线程,同一时间只能有一个线程被执行

    (4)pyhton的多线程没办法用到多核优势木业没有办法用到并行,但是可以用到并发

    (5)多核(cpu)的优势:运行快,计算快,cpu的功能是计算,遇到I/O没有什么用处

    (6)python的多线程有什么特点(重要)

      1、cpython的解释器由于GIL解释器锁的存在,导致基于cpython解释器写出来的多线程

        统一时间只能有一个线程出来运行,不能用上多核优势

      2、多核带来了什么好处?计算速度快,遇到I/O多核没有什么用处

    (7)开进程开销大,开进程对于多核优势没有什么用处

    解释:

      (1)在python中所有的数据都是共享的

      (2)python解释器只是一个软件,给你提供代码的运行解释并执行

      (3)假如线程可以利用多核优势:

        1、垃圾回收线程就会与其他的线程产生矛盾(因为是并行运行,垃圾回收线程机制就不会有用处)

        2、垃圾回收机制是Python解释器的优势相对于其他的语言

     3、GIL全局解释器锁

      (1)用锁的目的是为了让局部串行,其余的还是并发执行

      (2)GIL锁是保护垃圾回收机制有关的解释器的数据

    4、多进程和多线程的应用场景

      (1)python多进程用不到多核(纯I/O进程)

     (2)python多进程中多核是有用的(对于多计算型)

    (3)计算型

         线程要比进程花费时间长(线程不能串行,可以并发执行 来回切换)

    #计算密集型
    
    from multiprocessing import Process
    from threading import Thread
    import os,time
    def work():
        res=0
        for i in range(10000000):
            res*=1
    if __name__=="__main__":
        l=[]
        print(os.cpu_count())  #本机为四核
        start=time.time()
        for i in range(4):
            # p=Process(target=work) #耗时为run time is 2.872164249420166
            p=Thread(target=work) #耗时为run time is 6.84939169883728
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop=time.time()
        print("run time is %s"%(stop-start))
    计算密集型

    (4)I/O型,线程要比进程花费时间短(进程的开销大)

    5、死锁现象与递归锁

    (1)死锁

    (2)递归锁(解决死锁的方式)

    import time
    mutexA=mutexB=RLock()
    # mutexA=mutexB=Lock()
    
    class Mythread(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print("%s 拿到A锁"%self.name)
    
            mutexB.acquire()
            print("%s 拿到B锁"%self.name)
            mutexB.release()
    
            mutexA.release()
    
        def f2(self):
            mutexB.acquire()
            print("%s 拿到B锁"%self.name)
            time.sleep(0.1)
            mutexA.acquire()
            print("%s 拿到A锁"%self.name)
            mutexA.release()
    
            mutexB.release()
    
    if __name__=="__main__":
        for i in range(10):
            t=Mythread()
            t.start()
    死锁与递归锁

    6、协程

    (1)单线程下实现并发叫协程
    (2)只有遇到I/O切了才有意义(提升效率)
    (3)要实现单线程情况下的并发 要本着
    1、串行执行(没有切换,创建列表会有开销 可以忽略不计,数据UI越大 超过一定范围之后,
    列表的开销会增大)

    import time
    def consumer(res):
        """任务1:接收数据,处理数据"""
        pass
    def producer():
        """任务2:生产数据"""
        res=[]
        for i in range(100000):
            res.append(i)
        return res
    start=time.time()
    #串行执行
    res=producer()
    consumer(res)
    stop=time.time()
    print(stop-start)
    串行执行
    import time
    def consumer():
        """任务1:接收数据,处理数据"""
        while True:
            x=yield
            print("consumer")
    def producer():
        """任务2:生产数据"""
        g=consumer()
        next(g)
        for i in range(10000):
            print("producer")
            time.sleep(6)
            g.send(i)
    start=time.time()
    #基于yield保存状态,实现两个任务直接来回切换,即并发的效果
    #ps :如果每个任务中都加上打印,那么明显看到两个任务的打印是你一次我一次
    #即并发执行的
    producer()
    stop=time.time()
    print(stop-start)
    并发执行

    7、gevent模块  (明天讲)

  • 相关阅读:
    mysql alter table时的表锁是mysql服务层加的还是存储引擎加的
    show databases in redis
    Docker-compose中的使用技巧
    debian切换源
    C# MVC(File)控件多张图片上传加预览
    C# DateTime日期格式化
    DropDownList的使用,RadioButtonList的使用
    access数据库连接问题
    动态获取ul,li的数据
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/number1994/p/8195144.html
Copyright © 2020-2023  润新知