• Python3 并发编程3


    GIL全局解释器锁

    基本概念

    • global interpreter lock 全局解释器锁
    • GIL不是Python的特性, 是Cpython解释器的特性
    • GIL本质是一个互斥锁
    • 原因: Cpython解释器的内存管理不是线程安全的
    • 作用: 保证同一时间一个进程内只有一个线程在执行

    多线程的作用

    • 计算密集型---多进程, GIL原因, 一个进程内的线程只能并发, 不能并行
    • I/O密集型---多线程, 开启线程与切换线程的速度要快于进程
    # 计算密集型
    import time
    import os
    from multiprocessing import Process
    from threading import Thread
    
    
    # 计算密集型
    def task1():
        number = 0
        for i in range(100000000):
            number += 1
        print('done!')
    
    if __name__ == '__main__':
        start_time = time.time()
        lis = []
        for i in range(4):
            # p = Process(target=task1)  # 程序执行时间为16.711955785751343
            t = Thread(target=task1)  # 程序执行时间为26.467514038085938
            lis.append(t)
            t.start()
    
        for t in lis:
            t.join()
    
        end_time = time.time()
        print(f'程序执行时间为{end_time - start_time}')
    
    # I/O密集型
    import time
    import os
    from multiprocessing import Process
    from threading import Thread
    
    
    # I/O密集型
    def task2():
        time.sleep(1)
    
    
    if __name__ == '__main__':
        start_time = time.time()
        lis = []
        for i in range(20):
            # p = Process(target=task2)  # 程序执行时间为5.277301788330078
            t = Thread(target=task2)  # 程序执行时间为1.0040574073791504
            lis.append(t)
            t.start()
    
        for t in lis:
            t.join()
    
        end_time = time.time()
        print(f'程序执行时间为{end_time - start_time}')
    
    

    死锁现象

    • 两个或者两个以上的线程在执行过程中, 因为争夺资源而产生的相互等待的状况
    from threading import Thread, Lock
    import time
    
    mutex_a = Lock()
    mutex_b = Lock()
    
    
    class MyThread(Thread):
    
        def run(self):
            self.func1()
            self.func2()
    
        def func1(self):
            mutex_a.acquire()
            print(f'{self.name}拿到了锁a')
            mutex_b.acquire()
            print(f'{self.name}拿到了锁b')
            mutex_b.release()
            print(f'{self.name}释放了锁b')
            mutex_a.release()
            print(f'{self.name}释放了锁a')
    
        def func2(self):
            mutex_b.acquire()
            print(f'{self.name}拿到了锁b')
            # I/O操作
            time.sleep(1)
    
            mutex_a.acquire()
            print(f'{self.name}拿到了锁a')
            mutex_a.release()
            print(f'{self.name}释放了锁a')
            mutex_b.release()
            print(f'{self.name}释放了锁b')
    
    
    if __name__ == '__main__':
        for i in range(4):
            t = MyThread()
            t.start()
            
            
    '''
    Thread-1拿到了锁a
    Thread-1拿到了锁b
    Thread-1释放了锁b
    Thread-1释放了锁a
    Thread-1拿到了锁b
    Thread-2拿到了锁a
    '''
    
    

    递归锁

    • RLock 内部维护一个Lock和一个计数的counter, counter记录了acquire次数, 使得资源可以被多次请求
    • 直到一个线程所有的acquire都被release, 其他线程才能获取资源
    from threading import Thread, RLock
    import time
    
    mutex_a = mutex_b = RLock()
    
    
    class MyThread(Thread):
    
        def run(self):
            self.func1()
            self.func2()
    
        def func1(self):
            mutex_a.acquire()
            print(f'{self.name}拿到了锁a')
            mutex_b.acquire()
            print(f'{self.name}拿到了锁b')
            mutex_b.release()
            print(f'{self.name}释放了锁b')
            mutex_a.release()
            print(f'{self.name}释放了锁a')
    
        def func2(self):
            mutex_b.acquire()
            print(f'{self.name}拿到了锁b')
            # I/O操作
            time.sleep(3)
    
            mutex_a.acquire()
            print(f'{self.name}拿到了锁a')
            mutex_a.release()
            print(f'{self.name}释放了锁a')
            mutex_b.release()
            print(f'{self.name}释放了锁b')
    
    
    if __name__ == '__main__':
        for i in range(4):
            t = MyThread()
            t.start()
    
    '''
    Thread-1拿到了锁a
    Thread-1拿到了锁b
    Thread-1释放了锁b
    Thread-1释放了锁a
    Thread-1拿到了锁b
    
    ---间隔了3秒---
    
    Thread-1拿到了锁a
    Thread-1释放了锁a
    Thread-1释放了锁b
    Thread-2拿到了锁a
    Thread-2拿到了锁b
    Thread-2释放了锁b
    Thread-2释放了锁a
    Thread-2拿到了锁b
    
    ---间隔了3秒---
    
    Thread-2拿到了锁a
    Thread-2释放了锁a
    Thread-2释放了锁b
    Thread-4拿到了锁a
    Thread-4拿到了锁b
    Thread-4释放了锁b
    Thread-4释放了锁a
    Thread-4拿到了锁b
    
    ---间隔了3秒---
    
    Thread-4拿到了锁a
    Thread-4释放了锁a
    Thread-4释放了锁b
    Thread-3拿到了锁a
    Thread-3拿到了锁b
    Thread-3释放了锁b
    Thread-3释放了锁a
    Thread-3拿到了锁b
    Thread-3拿到了锁a
    Thread-3释放了锁a
    Thread-3释放了锁b
    '''
    

    信号量

    • from threading import Semaphore
    • 相当于多个互斥锁, 可以控制多个线程来访问数据 (可以控制访问资源的线程数量)
    • sm = Semaphore(5) 表示一次允许5个线程访问数据
    • acquire 一次, 括号内数字减一, release一次加一, 为0时限制其他线程访问
    from threading import Thread, Semaphore, current_thread
    import time
    
    # 一次允许5个线程访问数据
    sm = Semaphore(5)
    
    
    def task():
        sm.acquire()
        print(f'{current_thread().name}已运行...')
        time.sleep(3)
        sm.release()
    
    
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=task)
            t.start()
            
            
    '''
    Thread-1已运行...
    Thread-2已运行...
    Thread-3已运行...
    Thread-4已运行...
    Thread-5已运行...
    
    ---间隔了3秒---
    
    Thread-6已运行...
    Thread-7已运行...
    Thread-8已运行...
    Thread-9已运行...
    Thread-10已运行...
    
    --间隔了3秒---
    
    Thread-11已运行...
    Thread-12已运行...
    Thread-13已运行...
    Thread-14已运行...
    Thread-15已运行...
    
    ---间隔3秒---
    
    Thread-17已运行...
    Thread-16已运行...
    Thread-18已运行...
    Thread-19已运行...
    Thread-20已运行...
    '''
    
    

    线程队列

    • queue.Queue() FIFO 先进先出
    • queque.LifoQueue() LIFO 后进先出
    • queque.PriorityQueue() 优先级, 根据元祖内的数据排序
    import queue
    
    # 先进先出 FIFO
    q1 = queue.Queue()
    q1.put(1)
    q1.put(2)
    q1.put(3)
    
    print(q1.get())  # 1
    
    # 后进先出 LIFO
    q2 = queue.LifoQueue()
    q2.put(1)
    q2.put(2)
    q2.put(3)
    print(q2.get())  # 3
    
    # 优先级 按元祖内的数据排序
    q3 = queue.PriorityQueue()
    q3.put(('a',))
    q3.put(('b',))
    q3.put(('c',))
    print(q3.get())  # ('a',)
    
    
  • 相关阅读:
    最短路最基本算法———Floyd算法
    最短路最基本算法———Floyd算法
    浅谈最基础的三种背包问题
    浅谈最基础的三种背包问题
    Java中的反射机制Reflection
    Linux下抓包命令tcpdump的使用
    SSRF(服务端请求伪造)漏洞
    Cookie、Session和Token认证
    使用BurpSuite抓取HTTPS网站的数据包
    堆、栈和队列的区别
  • 原文地址:https://www.cnblogs.com/bigb/p/11729122.html
Copyright © 2020-2023  润新知