• 递归锁,队列


    1.线程为什么要有锁:

      全局解释器锁GIL 不能完全确保数据的安全(时间片轮转法)

      线程之间等的数据安全问题:

      +=,-=赋值操作不安全

      不涉及赋值操作的数据是安全的

    不安全:

    from threading import Lock,Thread
    n = 1500000
    def func():
        global n
        for i in range(1500000):
            n -= 1
    def func2():
        global n
        for i in range(1500000):
            n += 1
    if __name__ == '__main__':
        t_lst = []
        for i in range(10):
            t = Thread(target=func)
            t2 = Thread(target=func2)
            t.start()
            t2.start()
            t_lst.append(t)
            t_lst.append(t2)
        for t in t_lst:
            t.join()
        print('>>>>',n)
    

      加锁:

    from threading import Lock,Thread
    n = 150000
    def func(lock):
        global n
        for i in range(150000):
            lock.acquire()
            n -= 1
            lock.release()
    def func2(lock):
        global n
        for i in range(150000):
            lock.acquire()
            n += 1
            lock.release()
    if __name__ == '__main__':
        lock = Lock()
        t_lst = []
        for i in range(10):
            t = Thread(target=func,args=(lock,))
            t2 = Thread(target=func2,args=(lock,))
            t.start()
            t2.start()
            t_lst.append(t)
            t_lst.append(t2)
        for t in t_lst:
            t.join()
        print('>>>>',n)
    

      

    2:互斥锁与递归锁

      死锁现象:

        两把锁

        异步的

        操作的时候,一个线程抢到一把锁之后还要再去抢第二把锁

        一个线程抢到一把锁

        另一个线程抢到了另一把锁

    3:递归锁可以解决互斥锁的问题

      互斥锁:

        两把锁

        多个线程抢

      递归锁:

        一把钥匙

        多个线程抢

    递归锁好不好?

      递归锁并不是一个好的解决方案

      死锁现象的发生不是互斥锁的问题

      而是程序员的逻辑有问题导致的

      递归锁能够快速的解决死锁问题

    递归锁:

      迅速恢复服务 ,递归锁替换互斥锁

      在接下来的时间中慢慢把递归锁替换成互斥锁

        完善代码的逻辑

        提高代码的效率

    多个线程之间,用完一个资源再用另一个资源

    先释放一个资源,再去获取一个资源的锁

    死锁现象:

    import time
    from threading import Thread,Lock
    
    noodle_lock = Lock()
    fork_lock = Lock()
    def eat1(name):
        noodle_lock.acquire()
        print('%s拿到面条了' % name)
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        print('%s吃面' % name)
        time.sleep(0.3)
        fork_lock.release()
        print('%s放下叉子' % name)
        noodle_lock.release()
        print('%s放下面' % name)
    
    def eat2(name):
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        noodle_lock.acquire()
        print('%s拿到面条了' % name)
        print('%s吃面' % name)
        time.sleep(0.3)
        noodle_lock.release()
        print('%s放下面' % name)
        fork_lock.release()
        print('%s放下叉子' % name)
    
    if __name__ == '__main__':
        name_list = ['liming','lining']
        name_list2 = ['lijing', 'liling']
        for name in name_list:
            Thread(target=eat1,args=(name,)).start()
        for name in name_list2:
            Thread(target=eat2,args=(name,)).start()
    

      递归锁

    from threading import Thread,RLock
    rlock = RLock()
    def func(name):
        rlock.acquire()
        print(name,1)
        rlock.acquire()
        print(name,2)
        rlock.acquire()
        print(name,3)
        rlock.release()
        rlock.release()
        rlock.release()
    for i in range(10):
        Thread(target=func,args=('liming%s'%i,)).start()
    

      解决死锁问题,互斥锁修改位递归锁

    import time
    from threading import Thread,RLock#Lock
    
    # noodle_lock = Lock()
    # fork_lock = Lock()
    fork_lock = noodle_lock = RLock() #互斥锁改为递归锁
    def eat1(name):
        noodle_lock.acquire()
        print('%s拿到面条了' % name)
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        print('%s吃面' % name)
        time.sleep(0.3)
        fork_lock.release()
        print('%s放下叉子' % name)
        noodle_lock.release()
        print('%s放下面' % name)
    
    def eat2(name):
        fork_lock.acquire()
        print('%s拿到叉子了' % name)
        noodle_lock.acquire()
        print('%s拿到面条了' % name)
        print('%s吃面' % name)
        time.sleep(0.3)
        noodle_lock.release()
        print('%s放下面' % name)
        fork_lock.release()
        print('%s放下叉子' % name)
    
    if __name__ == '__main__':
        name_list = ['liming','lining']
        name_list2 = ['lijing', 'liling']
        for name in name_list:
            Thread(target=eat1,args=(name,)).start()
        for name in name_list2:
            Thread(target=eat2,args=(name,)).start()
    

      

    4:信号量

    import time
    from threading import Semaphore,Thread

    def func(index,sem):
    sem.acquire()
    print(index)
    time.sleep(1)
    sem.release()

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

      

    5.事件:检测数据库连接

      wait() 等待事件内的信号变为True

      set()  把信号变为True

      clear() 把信号变为False

      is_set 查看信号是否Ture

    import time
    import random
    from threading import Event,Thread
    def check():
        print('开始检测数据库连接')
        time.sleep(random.randint(1,5))  #模拟,真实测试时替换
        e.set() #
    
    def connect(e):
        for i in range(3):
            e.wait(0.5)
            if e.is_set():
                print('数据库连接成功')
            else:
                print('尝试连接数据库%s次失败' % (i+1))
        else:
            raise TimeoutError
    e = Event()
    Thread(target=connect,args=(e,)).start()
    Thread(target=check,args=(e,)).start()
    

     6.条件

      notify 控制流量, 通知有多少人可以通过了

      wait 在门口等待的所有人

      wait 使用前后都需要加锁

      notify 使用前后都要加锁

    from threading import Condition,Thread
    def func(con,index):
        print('%s在等待' % index)
        con.acquire()
        con.wait()
        print('%sdo something' % index)
        con.release()
    con = Condition()
    for i in range(100):
        t = Thread(target=func,args=(con,i))
        t.start()
    count = 100
    while count > 0:
        num = int(input('>>>:'))
        con.acquire()
        con.notify(num)
        count -= num
        con.release()
    
    # con.acquire()
    # con.notify_all() #一次放完
    # con.release()
    

    7.定时器:

    from threading import Timer
    def func():
        print('执行了')
    t = Timer(5,func) #5妙后执行func这个函数
    t.start()
    print('主线程')
    

    8.队列:

    #线程是安全 队列 :排队相关的逻辑(先进先出)
    import queue
    q = queue.Queue()
    q.put()
    q.get()
    q.put_nowait()
    q.get_nowait()
    

      qps 每秒接受的请求数:

      帮助维持程序相应的顺序

    后进先出

    from queue import LifoQueue  #后进先出
    #栈  完成算法
    lq = LifoQueue()
    lq.put(1)
    lq.put(2)
    lq.put(3)
    lq.put('a')
    lq.put('b')
    print(lq.get())
    print(lq.get())
    print(lq.get())
    

    优先级队列:应用VIP.

    #优先级队列,
    from queue import PriorityQueue
    pq = PriorityQueue()
    pq.put((15,'abc'))
    pq.put((5,'ghj'))
    pq.put((25,'ftr'))
    pq.put((25,'atr'))
    print(pq.get())
    print(pq.get())
    print(pq.get())
    print(pq.get())
    

      

    from queue import PriorityQueue
    pq = PriorityQueue()
    pq.put(35)
    pq.put(15)
    pq.put(25)
    print(pq.get())
    print(pq.get())
    print(pq.get())
    

      

    from queue import PriorityQueue
    pq = PriorityQueue()
    pq.put('c')
    pq.put('a')
    pq.put('b')
    print(pq.get())
    print(pq.get())
    print(pq.get())
    

      

      

      

        

        

  • 相关阅读:
    java实现猜生日
    java实现猜生日
    java实现猜生日
    自定义EL表达式,将对象转成json格式,关键代码
    Ajax提交post请求返回404错误
    spring-boot | 整合通用Mabatis 分页插件PageHelper
    公众号开发 jsp中<a>问题
    SpringBoot+Mybatis+ Druid+PageHelper 实现多数据源并分页
    纯JSP实现简单微信开发后台
    localStorage,sessionStorage,cookie使用场景和区别
  • 原文地址:https://www.cnblogs.com/lijinming110/p/9703737.html
Copyright © 2020-2023  润新知