• 线程理论和实操


    1.什么是线程

    进程其实不是一个执行单位. 进程是一个资源单位
    每个进程内自带一个线程. 线程才是cpu上的执行单位
    
    如果把操作系统比喻一座工厂
        在工厂中每造出一个车间 -> 启动一个进程
        每个车间至少有一条流水线 -> 每个进程至少有一个线程
    
    线程 -> 单指代码的执行过程
    进程 -> 资源的申请与销毁的过程
    

    2.进程vs线程

    1. 内存共享or隔离
        多个进程内存空间彼此隔离
        同一进程下的多个线程共享该进程内的数据
    2. 创造速度
        创建线程的速度要远远快与造进程
    

    3.创建线程的两种方式

    # -*- encoding:utf-8 -*-
    # @time: 2022/8/7 8:44
    # @author: Maxs_hu
    from threading import Thread
    import time
    
    
    # 方式1:
    def task(name):
        print('%s is running' % name)
        time.sleep(2)
        print('done')
    
    
    if __name__ == '__main__':
        t = Thread(target=task, args=('maxs_hu', ))
        t.start()
    
        print('主')  # 线程创建速度很快.
    """
    maxs_hu is running
    主
    done
    """
    
    
    # 方式2:
    class Mythreading(Thread):
        def run(self):
            print('%s is running' % self.name)
            time.sleep(3)
            print('%s is done' % self.name)
    
    
    if __name__ == '__main__':
        t = Mythreading()
        t.start()
        print('main')
    

    4.线程vs进程代码实现

    # -*- encoding:utf-8 -*-
    # @time: 2022/8/7 8:53
    # @author: Maxs_hu
    from threading import Thread
    from multiprocessing import Process
    
    
    # 线程的速度快于进程
    def task(name):
        print(f'{name} is running')
    
    
    if __name__ == '__main__':
        t = Thread(target=task, args=('子线程', ))
        p = Process(target=task, args=('子进程', ))
        p.start()
    
        t.start()
        print('main')
    
    
    # 同一进程内的线程共享线程内的资源
    x = 100
    
    def task():
        global x
        x = 1
    
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
        t.join()  # 等待线程执行完毕
        print(x)  # x的值被子线程修改
    
    
    # 查看pid
    import os
    
    
    def task():
        print('pid: %s' % os.getpid())
    
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
    
        print('主线程: %s' % os.getpid())
        # pid: 5232主线程: 5232
    
    

    5.守护线程

    # -*- encoding:utf-8 -*-
    # @time: 2022/8/7 9:09
    # @author: Maxs_hu
    from threading import Thread, current_thread
    import time
    
    
    # 守护进程会在本进程内的非守护进程的死掉之后跟着死掉
    # 守护线程其实守护的是整个进程的运行周期
    # def task():
    #     print('%s is running' % current_thread().name)
    #     time.sleep(2)
    #     print('%s is done' % current_thread().name)  # 如果主线程在这条之前运行完了. 就不回输出
    #
    #
    # if __name__ == '__main__':
    #     t = Thread(target=task)
    #     t.daemon = True  # 设置守护线程
    #     t.start()
    #     print('main')
    
    
    # 小案例
    def foo():
        print(123)
        time.sleep(3)
        print("end123")  # 这个没有输出
    
    
    def bar():
        print(456)
        time.sleep(1)
        print("end456")
    
    
    t1 = Thread(target=foo)
    t2 = Thread(target=bar)
    
    t1.daemon = True
    t1.start()
    t2.start()
    print("main-------")
    """
    123
    456
    main-------
    end456
    """
    

    6.守护线程

    # -*- encoding:utf-8 -*-
    # @time: 2022/8/7 9:24
    # @author: Maxs_hu
    
    
    # 什么是互斥锁:
    #   将多个并发任务对共享数据的修改变成串行, 以保证数据安全
    #   加上锁之后效率变低. 保证数据安全
    from threading import Thread, Lock
    import time
    x = 100
    
    
    # def task():
    #     global x
    #     temp = x
    #     time.sleep(0.1)  # 线程全部拿到temp = 100到这里睡了0.1秒. 后面修改数据就都是99. 不符合正常逻辑.
    #     x = temp - 1
    #
    #
    # if __name__ == '__main__':
    #     t_ls = []
    #     for i in range(100):
    #         t = Thread(target=task)
    #         t_ls.append(t)
    #         t.start()
    #
    #     for t in t_ls:  # 等待子线程运行完毕
    #         t.join()
    #
    #     print(x)
    
    
    mutex = Lock()
    
    
    def task():
        global x
        mutex.acquire()
        temp = x
        time.sleep(0.1)  # 线程全部拿到temp = 100到这里睡了0.1秒. 后面修改数据就都是99. 不符合正常逻辑.
        x = temp - 1
        mutex.release()
    
    
    if __name__ == '__main__':
        t_ls = []
        start_time = time.time()
        for i in range(100):
            t = Thread(target=task)
            t_ls.append(t)
            t.start()
    
        for t in t_ls:  # 等待子线程运行完毕
            t.join()
    
        print(x, time.time()-start_time)
    
    

    7.死锁现象和递归锁

    # -*- encoding:utf-8 -*-
    # @time: 2022/8/7 10:19
    # @author: Maxs_hu
    """
    什么是死锁现象:
        相当于两个人拿着对方家里的钥匙. 被锁门里面了
        互相等着拿对方的锁的现象
    怎么解决死锁现象:
        递归锁: Rlock原理
            给不同的锁赋值obj递归锁对象. 被赋值的锁被acquire多次. 就会在整体标记多次. 只要存在标记. 后面的线程就只能等着
            而只有release消除所有的标记次数. 才能开始抢锁. 从而解决死锁现象
    
        递归锁的特点:可以连续的acquire
    """
    
    
    from threading import Thread, Lock, active_count, RLock
    import time
    
    # mutexA=Lock()
    # mutexB=Lock()
    obj = RLock()  # 递归锁的特点:可以连续的acquire
    mutexA = obj
    mutexB = obj
    
    
    class Mythread(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s 拿到A锁' % self.name)
    
            mutexB.acquire()
            print('%s 拿到B锁' % self.name)
            mutexB.release()
    
            mutexA.release()
    
        def f2(self):
            mutexB.acquire()
            print('%s 拿到B锁' % self.name)
            time.sleep(1)
    
            mutexA.acquire()
            print('%s 拿到A锁' % self.name)
            mutexA.release()
    
            mutexB.release()
    
    
    if __name__ == '__main__':
        for i in range(10):
            t = Mythread()
            t.start()
        # print(active_count())
    
    

    8.信号量

    # -*- encoding:utf-8 -*-
    # @time: 2022/8/7 10:44
    # @author: Maxs_hu
    
    
    # 信号量: 同一时刻并发执行的任务数
    import time
    import random
    from threading import Thread, current_thread, Semaphore
    
    mutex = Semaphore(5)  # 设置同时并发量为5
    
    
    def task():
        with mutex:
            print('%s 在上厕所' % current_thread().name)
            time.sleep(random.randint(1, 3))
    
    
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=task)
            t.start()
    
    
  • 相关阅读:
    使用XLua在Unity中获取lua全局变量和函数
    RocketMQ存储设计的奥妙
    Composition API(常用部分)
    MySQL主从复制与读写分离
    火电安全事故vr模拟仿真培训强交互更真实
    conductor cluster server decision处理冲突解决方法
    【机器学习】特征选择之包裹式特征选择法
    尚硅谷wepack课程学习笔记
    Liunx中日志分析与网络设置(极其粗糙版)
    管理类联考——数学——汇总篇——记忆——歌诀记忆法
  • 原文地址:https://www.cnblogs.com/Maxs-message/p/16558672.html