• 3.多线程.md


    多线程

    进程与线程

    • 进程:指在系统中运行的一个应用程序,程序一旦运行就是进程;

      • 进程:资源分配的最小单位,一个进程至少有一个线程
        • 线程、内存、文件、网络句柄
        • 内存:每个进程的内存是相互独立的
        • 文件/网络句柄:他们是所有的进程所共有的,例如打开同一个文件,取抢同一个网络端口,这样的操作是被允许的
        • 抢占资源,导致死锁
    • 线程:系统分配处理器时间资源的基本单位,或者说进程之内独立执行的一个单元的执行流。

      • 线程:程序执行的最小单位
    • 汇总:

      • 1、进程要分配一大部分的内存,而线程只需要分配一部分栈就可以了
      • 2、一个程序至少有一个进程,一个进程至少有一个线程
      • 3、进程是资源分配的最小单位,线程是程序执行的最小单位
      • 4、一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行

    多线程---并发

    • 并行:两个CPU同时做事情

    • 并发:一个cpu,从执行A任务,接着执行b任务,又执行a任务,接着又执行b任务,循环执行

      • 1、使用线程可以把占据长时间的程序中的任务放到后台去处理
      • 2、用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
      • 程序的运行速度可能加快
      • 在一些等待的任务实现上如用户输入,文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等

    Threading模块

    • python3线程中常用的两个模块为:

      • _thread
      • threading(推荐使用)
    • thread模块已经被废弃了。用户可以使用threading模块代替。所以,在python3中不能再使用thread模块,为了兼容性,python3将thread重命名为_thread

    • 常用方法

      • run():用以表示线程活动的方法
      • start():启动线程的方法
      • join([time]):等待至线程中止,这阻塞调用线程直至线程的join()方法被调用中止--正常退出或者抛出未处理的异常--或者是可选的超时发生
      • isAlive():返回线程是否活动的
      • getName():返回线程名
      • setName():设置线程名
      • threading.currentThread():返回当前的线程变量
      • threading.enumerate():返回一个包含正在运行的线程list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
      • threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的效果

    多线程基础

    import time
    
    def doing(something):
        time.sleep(2)
        print('正在做>>>',something)
    start_time =time.time()
    doing('在上课')
    doing('在上班')
    end_time =time.time()
    print('总共耗时>>>',end_time-start_time)
    
    控制台输出:
    正在做>>> 在上课
    正在做>>> 在上班
    总共耗时>>> 4.010261297225952
    

    io密集型

    #-------------------------------------------------------------
    """
        需求:执行效率低
        优化:使用多线程
        io密集型
    """
    #-------------------------------------------------------------
    def doing(something):
        print('正在做>>>', something)
        time.sleep(2)
    
    start_time = time.time()
    
    #1-创建线程
    """
        target:函数名
        args:函数名对应的实参,元组形式
    """
    t1=threading.Thread(target=doing,args=('在上课',))
    t2=threading.Thread(target=doing,args=('在加班',))
    
    #2-启动线程
    t1.start()
    t2.start()
    end_time = time.time()
    print('总共耗时>>>', end_time - start_time)
    
    控制台输出
    正在做>>> 在上课
    正在做>>> 在加班总共耗时>>>
     0.0009598731994628906
    

    分析发现跟预期结果不一致,预期结果是大概是2s,现在是0s
    原因:直接启动线程:主线程(main)不等待子线程(t1/t2)完成就结束

    优化方案:

    3-阻塞主线程

    t1.join()
    t2.join() 
    
    控制台输出
    正在做>>> 在上课
    正在做>>> 在加班
    总共耗时>>> 2.0047731399536133
    
    

    计算密集型

    #-------------------------------------------------------------
    """
        需求:执行效率低
        优化:使用多线程
        计算密集型
    """
    #-------------------------------------------------------------
    def doing():
        dataNum=0
        for i in range(10000000):
            dataNum+=1
    
    start_time = time.time()
    
    #1-创建线程
    """
        target:你这个线程是做什么,需要执行的函数名
        args:函数名对应的实参,元组形式
        直接启动线程:主线程(main)不等待子线程(t1/t2)完成就结束
        需求:主线程退出之前需要等待子线程全部执行完
        优化:阻塞主线程 
        串行:总共耗时>>> 1.0268769264221191
    """
    #t1=threading.Thread(target=doing,args=('在上课',))
    #t2=threading.Thread(target=doing,args=('在加班',))
    #
    ##2-启动线程
    #t1.start()
    #t2.start()
    ##3-阻塞主线程
    #t1.join()
    #t2.join()
    doing()
    doing()
    end_time = time.time()
    print('总共耗时>>>', end_time - start_time)
    
    控制台输出:
    总共耗时>>> 1.0268769264221191
    

    多线程方式;
    改变部分的代码

    t1=threading.Thread(target=doing)
    t2=threading.Thread(target=doing)
    
    #2-启动线程
    t1.start()
    t2.start()
    #3-阻塞主线程
    t1.join()
    t2.join()
    
    控制台输出
    总共耗时>>> 1.0593979358673096
    

    通过对比发现对应计算密集型来说,使用串行和多线程,耗时一样
    对于cpython解释器GIL(全局解释器锁)),不管多少核 cpu同一时间只能处理一件事

    原因:
    多线程是并发:并发是来回切换执行不同的任务,导致计算密集型执行的时间比串行还长,因为来回切换也需要耗时

    守护线程:

    #-------------------------------------------------------------
    """
        需求:执行效率低
        优化:使用多线程
        守护线程
        主线程想满足一个条件就退出,使用多线程直接不能直接退出主线程
    """
    #-------------------------------------------------------------
    def doing():
        while True:
            print('我在doing')
            time.sleep(1)
    
    start_time = time.time()
    
    #1-创建线程
    """
        target:你这个线程是做什么,需要执行的函数名
        args:函数名对应的实参,元组形式
        直接启动线程:主线程(main)不等待子线程(t1/t2)完成就结束
        需求:主线程退出之前需要等待子线程全部执行完
        优化:阻塞主线程 
        串行:总共耗时>>> 1.0268769264221191
    """
    t1=threading.Thread(target=doing)
    t2=threading.Thread(target=doing)
    
    #2-启动线程
    t1.start()
    t2.start()
    #3-阻塞主线程
    #t1.join()
    #t2.join()
    end_time = time.time()
    for i in range(3):
        print('**********主线程正在执行*******')
    print('**********主线程结束*******')
    print('总共耗时>>>', end_time - start_time)
    
    
    控制台输出:
    死循环
    我在doing
    我在doing**********主线程正在执行*******
    
    **********主线程正在执行*******
    **********主线程正在执行*******
    **********主线程结束*******
    总共耗时>>> 0.0009987354278564453
    我在doing我在doing
    
    我在doing我在doing
    
    我在doing我在doing
    
    我在doing我在doing
    
    我在doing我在doing
    

    分析:
    主线程一直无法退出
    优化:
    增加守护线程 setdaemon(True)
    在以下位置增加守护部分代码

    t1=threading.Thread(target=doing)
    t2=threading.Thread(target=doing)
    
    t1.setDaemon(True)#守护
    t2.setDaemon(True)
    
    #2-启动线程
    t1.start()
    t2.start()
    
    控制台输出
    我在doing
    我在doing
    **********主线程正在执行*******
    **********主线程正在执行*******
    **********主线程正在执行*******
    **********主线程结束*******
    总共耗时>>> 0.0009744167327880859
    
  • 相关阅读:
    tableView cell 设置圆角 响应链
    iOS
    git code 初次上传
    隐藏导航栏,偏移20PX
    Mysql数据库远程连接
    umeng推送, 生产环境deviceToken失效可能原因
    KeyChainWrapper
    UIVisualEffectView(高斯模糊效果)
    UVA 11582 Colossal Fibonacci Numbers! 快速幂
    HDU 2859 Phalanx DP
  • 原文地址:https://www.cnblogs.com/xiehuangzhijia/p/14983991.html
Copyright © 2020-2023  润新知