• 线程全局修改、死锁、递归锁、信号量、GIL以及多进程和多线程的比较


    线程全局修改

    x = 100
    def func1():
        global x
        print(x)
        changex()
        print(x)
    def changex():
        global x
        x = 50
    
    func1()
    
    """
    100
    
    50
    """
    

    线程锁

    from threading import Thread, Lock
    
    x = 0
    mutex = Lock()
    def task():
        global x
        mutex.acquire() #加了锁之后就能保证每次只有一个运行,就不会出现数据丢失现象,不过效率会降低
        for i in range(100000):
            x = x + 1
        """
        如果不加锁,那么(以下的情况属于假设):
            t1 的 x 刚拿到0(属于IO) 保存好状态,这时候CPU切换给t2运行。
            t2 的 x拿到 0 并进行+1 操作     这时候x是1(运行完CPU切换)
            t1 又获得运行了 x = 0 并进行+1操作  这时候x也是1
            ****************************
            经过上面三步,是加了2次1,而真实运算出来的应该是+2,实际上只是加了1
            这就是为什么不加锁本来应该是300000,但是实际上却小于这个数的原因
            这就会产生数据安全问题
        """
        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
    
    lock1 = Lock()
    # lock2 = lock1 #这种情况相当于只有一把锁,
    # 所以抢到了锁1之后没办法再抢锁2了,就会卡在(Thread-1 抢到了锁1)
    lock2 = Lock()
    class DeadLock(Thread):
        def run(self):
            self.task1()
            self.task2()
    
        def task1(self):
            lock1.acquire()
            print(f'{self.name} 抢到了锁1')
            lock2.acquire()
            print(f'{self.name} 抢到了锁2')
            lock2.release()
            print(f'{self.name} 释放了锁2')
            lock1.release()
            print(f'{self.name} 释放了锁1')
        def task2(self):
            # 这里如果抢锁2,就会出现死锁现象,就会卡在这
            # lock2.acquire()
            # print(f'{self.name} 抢到了锁2')
            # 这里如果抢锁1,就不会出现死锁现象,会一直运行下去
            # lock1.acquire()
            # print(f'{self.name} 抢到了锁1')
            lock2.acquire()
            print(f'{self.name} 抢到了锁2')
            lock1.release()
            print(f'{self.name} 释放了锁1')
            lock2.release()
            print(f'{self.name} 释放了锁2')
    
    for i in range(3):
        t = DeadLock()
        t.start()
        
        
    *******死锁问题********
    ###两个线程
    # 线程1拿到了(锁2),想要往下执行需要(锁1),
    # 线程2拿到了(锁1),想要往下执行需要(锁2),
    # 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁
    
    

    递归锁

    from threading import Thread,RLock
    '''
    递归锁 在同一个线程内可以被多次acquire
    如何释放 内部相当于维护了一个计数器
    也就是说同一个线程 acquire了几次
    就要release几次
    
    '''
    lock1 = RLock()
    lock2 = lock1
    class Recursion(Thread):
        def run(self):
            self.task1()
            self.task2()
    
        def task1(self):
            lock1.acquire()
            print(f'{self.name}抢到了 锁1')
            lock2.acquire()
            print(f'{self.name}抢到了 锁2')
            lock1.release()
            print(f'{self.name}释放了 锁1')
            lock2.release()
            print(f'{self.name}释放了 锁2')
        def task2(self):
            lock1.acquire()
            print(f'{self.name}抢到了 锁1')
            lock2.acquire()
            print(f'{self.name}抢到了 锁2')
            lock1.release()
            print(f'{self.name}释放了 锁1')
            lock2.release()
            print(f'{self.name}释放了 锁2')
    
    for i in range(3):
        t = Recursion()
        t.start()
        
    #可以正常执行,不会出现差错
    

    信号量

    from threading import Thread,currentThread,Semaphore
    import time
    
    def task():
        sm.acquire()
        time.sleep(2)
        print(f'{currentThread().name} is running!')
        sm.release()
    
    
    sm = Semaphore(5) #(可以一次性发5个,信号量就是自定义最大连接数5个)
    for i in range(15):
        t = Thread(target=task)
        t.start()
    """
    会分3组,
    
    每组5个打印出来
    """
    

    GIL(全局解释器锁)

    """
    ###在Cpython解释器中有一把GIL(全局解释器锁),GIL锁本质是一把互斥锁。
    
    
    导致了同一个进程下,同一时间只能运行一个进程,无法利用多核优势,同一进程
    下多个线程只能实现并发不能实现并行。
    
    
    
    
    
    为什么要有GIL?
    因为Cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁。
    
    导致了同一进程下,同一时间只能运行一个线程,无法利用多核优势。
    
    
    
    
    分析:
    	我们有四个任务需要处理,处理方式肯定要玩出并发的效果,解决方案可以是:
    	方案一:开启四个进程
    	方案二:一个进程下,开启四个线程
    
    
    
    
    """
    #******计算密集型******
    #推荐使用多进程
    from threading import Thread
    from multiprocessing import Process
    import time
    
    def work1():
        res = 0
        for i in range(100000000):
            res *= i
    
    if __name__ == '__main__':
        t_list = []
        start = time.time()
        for i in range(5):
            t = Process(target=work1)
            # t = Thread(target=work1())
            t.start()
            t_list.append(t)
        for t in t_list:
            t.join()
        end = time.time()
        print('多进程', end - start)  #多进程 22.06749701499939
        # print('多线程', end - start)  #多线程 41.195727586746216
    
    ******IO密集型******
    #推荐使用多线程
    
    
    from threading import Thread
    from multiprocessing import Process
    import time
    
    def task1():
        x = 1+1
        time.sleep(3)
    
    if __name__ == '__main__':
        t_list = []
        start = time.time()
        for i in range(4):
            # t = Thread(target=task1)
            t = Process(target=task1)
            t_list.append(t)
            t.start()
        for t in t_list:
            t.join()
        end = time.time()
        # print('多线程', end - start) #多线程 3.002215623855591
        print('多进程', end - start) #多进程 3.8354334831237793
    
    
    
    
    
    
    
    
  • 相关阅读:
    格式化日期为yyyy-MM-dd
    JavaScript 原型
    SSD 车辆检测 实现
    Unity模拟自动驾驶方向盘角度预测
    交通标识牌识别
    cifar-10 No such file or directory: '/home/ /.keras/datasets/cifar-10-batches-py/data_batch_1'
    Keras 使用多层感知器 预测泰坦尼克 乘客 生还概率
    else
    Keras源码下载记录
    import cv2 失败 ImportError:DLL load fail:找不到指定模块
  • 原文地址:https://www.cnblogs.com/michealjy/p/11545468.html
Copyright © 2020-2023  润新知