zoukankan      html  css  js  c++  java
  • GIL全局解释器锁,多线程的作用,死锁现象,信号量(了解),线程队列。

    GIL全局解释器锁:

    python解释器:

    1.Cpython C ,

    2.Jpython java ,

    3.Ppython Python

    GIL全局解释器锁:

    基于Cpython来研究全局解释器锁。

    1.GIL本质上是一个互斥锁。

    2.GIL的为了阻止当前进程内执行多个线程。

    ​ 单个进程下的多个线程无法实现并发,但能实现并发

    3.这把锁主要是因为CPython的内存管理不是'线程安全'的。

    ​ 内存管理

    ​ 垃圾回收机制

    GIL的存在就是为了保证线程安全的。

    注意: 多个线程过来执行,一旦遇到IO操作,就会立马释放GIL解释器锁,交给下一个先进来的线程.
    

    代码演示

    import time
    from threading import Thread, current_thread
    
    number = 100
    
    def task():
        global number
        number2 = number
        # time.sleep(1)
        number = number2 - 1
        print(number, current_thread().name)
    
    for line in range(100):
        t = Thread(target=task)
        t.start()
        #
    99 Thread-1
    98 Thread-2
    .
    .
    .
    1 Thread-99
    0 Thread-100
    

    多线程的作用:

    站在两个角度去看问题:
    

    四个任务, 计算密集型, 每个任务需要10s:

    单核:

    开启进程

    消耗资源过大
    4个进程: 40s

    开启线程

    消耗资源远小于进程

    • 4个线程: 40s

    多核:

    开启进程

    并行执行,效率比较高
    4个进程: 10s

    开启线程

    并发执行,执行效率低.
    4个线程: 40s

    四个任务, IO密集型, 每个任务需要10s:

    单核:

    开启进程

    3消耗资源过大
    34个进程: 40s

    开启线程

    消耗资源远小于进程
    4个线程: 40s

    多核:

    开启进程

    并行执行,效率小于多线程,因为遇到IO会立马切换CPU的执行权限
    4个进程: 40s + 开启进程消耗的额外时间

    开启线程

    并发执行,执行效率高于多进程

    4个线程: 40s

    rom threading import Thread
    from multiprocessing import Process
    import os
    import time
    
    # 计算密集型
    def work1():
        number = 0
        for line in range(100000000):
            number += 1
    
    # IO密集型
    def work2():
        time.sleep(1)
    
    if __name__ == '__main__'
    
    # IO密集型
        print(os.cpu_count())  # 6
        # 开始时间
        start_time = time.time()
        list1 = []
        for line in range(40):
            # p = Process(target=work2)  # 程序执行时间4.445072174072266
            p = Thread(target=work2)  # 程序执行时间1.009237289428711
    
            list1.append(p)
            p.start()
    
        for p in list1:
            p.join()
        end_time = time.time()
    
        print(f'程序执行时间{end_time - start_time}')
    
    
    '''
    在计算密集型的情况下:
        使用多进程
        
    在IO密集型的情况下:
        使用多线程
        
    高效执行多个进程,内多个IO密集型的程序:
        使用 多进程 + 多线程
    '''
    

    死锁现象

    from threading import Lock,Thread,current_thread
    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}释放锁a')
            
       def func2(self):
        mutex_b.acquire()
        print(f'用户{self.name}抢到锁b')
        # IO操作
        rime.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')
        
    for line in range(10):
    	t = MyThread()
        t.start()
        
        注意:
        	锁不能乱用
    

    递归锁(了解)

    ​ 用于解决死锁问题。

    RLock:比喻成万能钥匙,可以提供给多个人用,但是第一个使用的时候,会对该锁做一个引用计数.只有引用计数为0,才能真正释放让另一个去使用。

    from threading import RLock, Thread, Lock
    import time
    
    mutex_a = mutex_b = Lock()
    
    class MyThread(Thread):
    
        # 线程执行任务
        def run(self):
            self.func1()
            self.func2()
    
        def func1(self):
            mutex_a.acquire()
            # print(f'用户{current_thread().name}抢到锁a')
            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')
            # IO操作
            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')
    
    for line in range(10):
        t = MyThread()
        t.start()
    
    

    信号量(了解):

    互斥锁:

    比喻成一个家用马桶. 同一时间只能让一个人去使用

    信号量:

    比喻成公厕多个马桶. 同一时间可以让多个人去使用

    from threading import Semaphore, Lock
    from threading import current_thread
    from threading import Thread
    import time
    
    sm = Semaphore(5)  # 5个马桶
    mutex = Lock()  # 5个马桶
    
    def task():
        sm.acquire()
        print(f'{current_thread().name}执行任务')
        time.sleep(1)
        sm.release()
        # mutex.release()
    
    for line in range(20):
        t = Thread(target=task)
        t.start()
    

    线程队列

    线程Q(了解级别1): 线程队列 面试会问: FIFO

    • FIFO队列: 先进先出
    • LIFO队列: 后进先出
    • 优先级队列: 根据参数内,数字的大小进行分级,数字值越小,优先级越高
    import queue
    
    # 普通的线程队列: 先进先出
    q = queue.Queue()
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())  # 1
    
    # LIFO队列: 后进先出
    q = queue.LifoQueue()
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())  # 3
    
    
  • 相关阅读:
    七 HBase表结构设计
    六 一行数据存储到文件的过程。
    五、数据模型特殊属性
    四 数据模型操作
    三、 数据模型概念
    二、 HBase核心功能模块。
    一、 Hbase特性 3v特性,Volume(量级) Varity(种类) Velocity(速度)
    windows下安装redis
    redis缓存穿透和缓存雪崩
    java多线程四种实现方法
  • 原文地址:https://www.cnblogs.com/WQ577098649/p/11729215.html
Copyright © 2011-2022 走看看