• python 线程(thread)阻塞


    本文链接:https://www.cnblogs.com/tujia/p/13684251.html

    背景:来观察测试一下python 线程(Thread)的阻塞、普通线程和守护线程有什么区别、线程池又是什么

    一、公共代码

    首先先贴上一些公共代码,下面的例子都基于这份公共代码运行(注:替换xxx的内容)

    import time
    import threading
    from concurrent.futures import ThreadPoolExecutor
    
    
    def worker(name):
        print('%s start...' % name)
        time.sleep(2)
        print('%s done.' % name)
    
    
    def xxx():
        pass
    
    
    if __name__ == '__main__':
        xxx()

    二、单线程阻塞

    def 单线程阻塞():
        t = threading.Thread(target=worker, args=('张三',))
        t.start()
        # 阻塞
        t.join()
        print('Finished')

    运行结果:

    解释:阻塞线程的情况下,程序会先等待线程任务执行完,再往下执行其他代码 

    三、单线程不阻塞

    def 单线程不阻塞():
        t = threading.Thread(target=worker, args=('李四',))
        t.start()
        print('Finished')

    运行结果:

    解释:不阻塞线程的情况下,程序会直接往下走,线程任务是后完成的(因为我在线程任务里加了 sleep),类似于异步;同时,我们还可以发现,程序(主线程)执行完最后一行代码之后,如果线程任务还没完成,程序是不会马上死掉的,还是会等线程任务执行完才会结束程序。

    四、多线程的错误阻塞

    def 多线程的错误阻塞():
        t1 = threading.Thread(target=worker, args=('张三',))
        t1.start()
        t1.join()
        t2 = threading.Thread(target=worker, args=('李四',))
        t2.start()
        t2.join()
        print('Finished')

    运行结果:

    解释:t1.join 直接阻塞了程序,t2还没start,t1.join阻塞程序直到t1的任务已完成。所以会看到 张三 done 之后,李四 才能 start

    五、多线程的正确阻塞

    def 多线程的正确阻塞():
        t1 = threading.Thread(target=worker, args=('张三',))
        t2 = threading.Thread(target=worker, args=('李四',))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print('Finished')

    运行结果:

      

    解释:需要将所以子线程都start之后,才能阻塞(join);线程任务也不是按顺序完成了,哪个先完成,得看哪个线程任务耗时少,也有可能会同时完成(并发)

    按下面代码,修改一下worker函数,给李四加一下速,再执行一次看看:

    def worker(name):
        print('%s start...' % name)
        time.sleep(2 if name == '张三' else 1)
        print('%s done.' % name)

    注:这次是李四先done了~

    温馨提示:测试完记得把 worker 函数改回原来的样子,下面例子是以原版的 worker 为基础的

    六、多线程不阻塞

    def 多线程不阻塞():
        t1 = threading.Thread(target=worker, args=('张三',))
        t2 = threading.Thread(target=worker, args=('李四',))
        t1.start()
        t2.start()
        print('Finished')

    运行结果:

      

    解释: 参考上面单线程不阻塞↑,不阻塞的情况下,也是会等待全部线程任务执行完成才结束程序的。多线程有一定的并发现象

    七、守护线程(后台线程)阻塞

    def 守护线程阻塞():
        t1 = threading.Thread(daemon=True, target=worker, args=('张三',))
        t2 = threading.Thread(daemon=True, target=worker, args=('李四',))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print('Finished')

    运行结果:

     

    解释:这里看着上面的普通线程没有什么区别的,具体的区别看下面↓↓↓

    八、守护线程不阻塞

    def 守护线程不阻塞():
        t1 = threading.Thread(daemon=True, target=worker, args=('张三',))
        t2 = threading.Thread(daemon=True, target=worker, args=('李四',))
        t1.start()
        t2.start()
        print('Finished')

    运行结果:

    解释:可以看到和”多线程不阻塞“很不一样,主程序并不会等待子线程完成任务才结束。而是直接就结束了。这是守护线程(后台线程)的一个特点:不阻塞的情况下,后台线程(守护线程)会在主线程结束的时候自动死掉

    九、守护线程不阻塞但主线程比较晚结束

    def 守护线程不阻塞但主线程比较晚结束():
        t1 = threading.Thread(daemon=True, target=worker, args=('张三',))
        t2 = threading.Thread(daemon=True, target=worker, args=('李四',))
        t1.start()
        t2.start()
        time.sleep(5)
        print('Finished')

    运行结果:

    解释:这里的主线程并没有等子(守护)线程,只是主线程耗时比子线程还要久,子线程先执行完毕了 

    十、线程池

    def 线程池():
        with ThreadPoolExecutor(max_workers=3) as p:
            p.submit(worker, '张三')
            p.submit(worker, '李四')
        print('Finished')

    运行结果:

      

    解释:线程池并没有 join 方法,但它默认就是阻塞的。运行结果基本和“多线程的正确阻塞”一样,只是线程池比较方便管理~

    本文链接:https://www.cnblogs.com/tujia/p/13684251.html


    完。 

  • 相关阅读:
    sed
    UCOSIII(二)
    UCOSIII(一)
    IIC
    SPI
    vii
    find
    grep
    Scrum项目4.0
    Scrum项目3.0
  • 原文地址:https://www.cnblogs.com/tujia/p/13684251.html
Copyright © 2020-2023  润新知