zoukankan      html  css  js  c++  java
  • day 39 线程锁,死锁问题,递归锁,信号量,gil全局解释锁

    线程锁

    #因为同一进程内的线程是共享资源的,当多个线程同时操作一个变量时,可能会因为线程的切换,导致

    变量值的错误,所以需要线程锁来保证一个线程运行完,再继续下一个线程

    from threading import Thread,Lock

    x = 0
    mutex = Lock()
    def task():
    global x
    # mutex.acquire()
    for i in range(200000):
    x = x+1
    # t1 的 x刚拿到0 保存状态 就被切了
    # t2 的 x拿到0 进行+1 1
    # t1 又获得运行了 x = 0 +1 1
    # 思考:一共加了几次1? 加了两次1 真实运算出来的数字本来应该+2 实际只+1
    # 这就产生了数据安全问题.
    # mutex.release()

    if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t2.start()
    t3.start()

    t1.join()
    t2.join()
    t3.join()
    print(x)


    死锁问题
    from threading import Thread,Lock
    mutex1 = Lock()
    mutex2 = Lock()
    import time
    class MyThreada(Thread):
    def run(self):
    self.task1()
    self.task2()
    def task1(self):
    mutex1.acquire()
    print(f'{self.name} 抢到了 锁1 ')
    mutex2.acquire()
    print(f'{self.name} 抢到了 锁2 ')
    mutex2.release()
    print(f'{self.name} 释放了 锁2 ')
    mutex1.release()
    print(f'{self.name} 释放了 锁1 ')

    def task2(self):
    mutex2.acquire()
    print(f'{self.name} 抢到了 锁2 ')
    time.sleep(1)
    mutex1.acquire()
    print(f'{self.name} 抢到了 锁1 ')
    mutex1.release()
    print(f'{self.name} 释放了 锁1 ')
    mutex2.release()
    print(f'{self.name} 释放了 锁2 ')


    for i in range(3):
    t = MyThreada()
    t.start()

    # 两个线程
    # 线程1拿到了(锁头2)想要往下执行需要(锁头1),
    # 线程2拿到了(锁头1)想要往下执行需要(锁头2)
    # 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁头.


    递归锁
    from threading import Thread,Lock,RLock
    # 递归锁 在同一个线程内可以被多次acquire
    # 如何释放 内部相当于维护了一个计数器 也就是说同一个线程 acquire了几次就要release几次
    # mutex1 = Lock()
    # mutex2 = Lock()
    mutex1 = RLock()
    mutex2 = mutex1

    import time
    class MyThreada(Thread):
    def run(self):
    self.task1()
    self.task2()
    def task1(self):
    mutex1.acquire()
    print(f'{self.name} 抢到了 锁1 ')
    mutex2.acquire()
    print(f'{self.name} 抢到了 锁2 ')
    mutex2.release()
    print(f'{self.name} 释放了 锁2 ')
    mutex1.release()
    print(f'{self.name} 释放了 锁1 ')

    def task2(self):
    mutex2.acquire()
    print(f'{self.name} 抢到了 锁2 ')
    time.sleep(1)
    mutex1.acquire()
    print(f'{self.name} 抢到了 锁1 ')
    mutex1.release()
    print(f'{self.name} 释放了 锁1 ')
    mutex2.release()
    print(f'{self.name} 释放了 锁2 ')


    for i in range(3):
    t = MyThreada()
    t.start()




    信号量
    #相当于一个锁有五把钥匙,只能有五个线程同时领取钥匙,之后的线程必须等前面的线程释放钥匙
    from threading import Thread,currentThread,Semaphore
    import time

    def task():
    sm.acquire()
    print(f'{currentThread().name} 在执行')
    time.sleep(3)
    sm.release()

    sm = Semaphore(5)
    for i in range(15):
    t = Thread(target=task)
    t.start()


    GIL全局解释器锁
    在Cpython解释器中有一把GIL锁(全局解释器锁),GIl锁本质是一把互斥锁。

    导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势.
    同一个进程下多个线程只能实现并发不能实现并行.

    为什么要有GIL?
    因为cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁.


    分析:
    我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:
    方案一:开启四个进程
    方案二:一个进程下,开启四个线程

    计算密集型 推荐使用多进程
    每个都要计算10s
    多线程
    在同一时刻只有一个线程会被执行,也就意味着每个10s都不能省,分开每个都要计算10s,共40.ns
    多进程
    可以并行的执行多个线程,10s+开启进程的时间

    io密集型 推荐多线程
    4个任务每个任务90%大部分时间都在io.
    每个任务io10s 0.5s
    多线程
    可以实现并发,每个线程io的时间不咋占用cpu, 10s + 4个任务的计算时间
    多进程
    可以实现并行,10s+1个任务执行的时间+开进程的时间
    # 如果一个线程抢掉了GIL,如果遇到io或者执行时间过长(cpu被剥夺),
    # 会强行释放掉GIL锁,以便其他的线程抢占GIL



    性能比较
    from threading import Thread
    from multiprocessing import Process
    import time

    计算密集型:
    def work1():
    res=0
    for i in range(100000000): #1+8个0
    res*=i

    if __name__ == '__main__':
    t_list = []
    start = time.time()
    for i in range(4):
    # t = Thread(target=work1)
    t = Process(target=work1)
    t_list.append(t)
    t.start()
    for t in t_list:
    t.join()
    end = time.time()
    # print('多线程',end-start) # 多线程 15.413789510726929
    print('多进程',end-start) # 多进程 4.711405515670776



    io密集型:
    def work1():
    x = 1+1
    time.sleep(5)
    x=3

    if __name__ == '__main__':
    t_list = []
    start = time.time()
    for i in range(4):
    t = Thread(target=work1)
    # t = Process(target=work1)
    t_list.append(t)
    t.start()
    for t in t_list:
    t.join()
    end = time.time()
    print('多线程',end-start) # 多线程 5.002625942230225
    #print('多进程',end-start) # 多进程 5.660863399505615






































  • 相关阅读:
    很好的学习idea工具的教程
    事件绑定
    接口出现问题
    IDEA快捷方式
    源代码编译安装Python3.5.2
    CentOS7使用无线网卡
    MySql5.7.12设置log-bin
    报表传递参数控制数据权限
    python将png转为pkm
    WebGL纹理详解——压缩纹理的使用
  • 原文地址:https://www.cnblogs.com/wwei4332/p/11542376.html
Copyright © 2011-2022 走看看