zoukankan      html  css  js  c++  java
  • 第一阶段:Python开发基础 day39 多线程的进阶补充内容

    昨日回顾

    '''
    cpu最小的执行单位:线程
    
    进程 资源集合
    线程 执行单位
    
    操作系统 --> 工厂
    进程     --> 车间
    线程(cpu)--> 流水线(电源)
    
    
    进程的内存空间彼此隔离
    线程共享同一份资源
    '''
    ### 方式一
    # from threading import Thread
    #
    # def task():
    #     pass
    #
    # # if __name__ == '__main__':
    # t = Thread(target= task)
    # t.start()
    
    ### 方式二 类
    # pass
    
    #### 创建速度
    # 进程需要申请内存空间 慢
    # 线程相当于直接告诉操作系统去干个什么活.  快
    
    
    ### 线程共享资源
    
    ### 线程的join方法: 等待被join的线程结束
        # 进程的join:等待被join的进程结束
    ### 线程其他的相关用法: getname setname enumerate() currentThread
    
    ### 守护线程: 守护的是进程运行周期
    

    一、线程锁

    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个任务执行的时间+开进程的时间
    

    六、多进程vs多线程

    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)
    #
    #
    # 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
    
  • 相关阅读:
    flutter 刷新和初始化
    flutter 复杂数据模型 转换
    flutter 刷新组件
    flutter wrap 流式布局
    添加横纵布局 和 页面保活
    跳转首页结构并且加载launch插件
    迟到的AFO
    [ELSE]自闭选手的自我修养
    [题解]UOJ#41 矩阵变换
    [题解]HDU 3555 Bomb
  • 原文地址:https://www.cnblogs.com/foreversun92/p/11542686.html
Copyright © 2011-2022 走看看