zoukankan      html  css  js  c++  java
  • ~~并发编程(十):线程方法~~

    进击のpython

    *****

    并发编程——线程方法


    开启了线程之后,就要学习一下对应的方法

    本小节对线程的一些方法进行简单的理解:

    1.Thread的join方法

    2.Thread的terminate与is_alive


    Thread的join方法

    join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)

    ​ timeout是可选的超时时间

    首先,系统在运行的过程中可能会出现这样的情况:

    1.主线程和子线程彼此独立,在都完成运行之后,由系统进行统一回收

    2.主线程等子进程运行完毕之后再执行

    第一种情况好说,第二种情况就需要有一种机制能够让主线程检测子进程是否运行完毕

    在子线程执行完毕后才继续执行,否则一直在原地阻塞,这就是join方法的作用

    from threading import Thread
    
    
    def work():
        print('我是子线程')
    
    
    if __name__ == '__main__':
        n = 100
        t = Thread(target=work)
        t.start()
        # t.join()
        print('我是主线程')
    
    

    在没有利用join方法的时候,执行顺序是这样的

    我是子线程我是主线程
    # 因为太快了,就打在一行了
    

    利用join之后,执行顺序就变成

    我是子线程
    我是主线程
    

    可以看到,主线程的代码在等待子进程代码运行结束才开始执行

    那是变成串行了吗???

    import time
    from threading import Thread
    
    
    def work(s):
        time.sleep(s)
        print('我是子线程')
    
    
    if __name__ == '__main__':
        n = 100
        t = Thread(target=work, args=(1,))
        t1 = Thread(target=work, args=(1,))
        t2 = Thread(target=work, args=(1,))
        start_time = time.time()
        t.start()
        t1.start()
        t2.start()
        t.join()
        t1.join()
        t2.join()
        print('我是主线程', time.time() - start_time)
    
    

    如果将join理解成串行,那么,子程序的执行时间应该是1+1+1 = 3s多

    先执行t,睡1s,再执行t1,睡1s,再执行t2,睡1s

    那我们来看一下执行结果:

    我是子线程
    我是子线程
    我是子线程
    我是主线程 1.002457857131958
    

    时间是1s多,说明不是串行,依旧是并发执行

    在开始介绍过,join是主线程等待子线程运行结束,再运行

    t t1 t2 都是子线程,彼此不需要等待,是并发执行的状态

    所以子线程互相都是共享时间的,都是在执行的

    而当子线程中1s的执行完了,也就意味着所有的子线程执行完毕了

    才会执行主线程,所以子线程的执行时间只有1s多

    上述的代码也可以优化一下:

    import time
    from threading import Thread
    
    
    def work(s):
        time.sleep(s)
        print('我是子线程')
    
    
    if __name__ == '__main__':
        n = 100
        t = Thread(target=work, args=(1,))
        t1 = Thread(target=work, args=(1,))
        t2 = Thread(target=work, args=(1,))
        l = [t,t1,t2]
        start_time = time.time()
        for i in l:
            i.start()
        for i in l:
            i.join()
        print('我是主线程', time.time() - start_time)
    
    

    Thread的其他方法

    1. is_alive 线程是否存活
    2. getName 返回线程名
    3. setName 设置线程名
    4. threading.currentThread 返回当前的线程变量
    5. threading.enumerate 返回一个包含正在运行的线程的list,正在运行指线程启动后、结束前,不包括启动前和终止后的线程
    6. threading.activeCount 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
    from threading import Thread
    import threading
    
    
    def work():
        import time
        time.sleep(3)
        print(threading.current_thread().getName())
    
    
    if __name__ == '__main__':
        # 在主进程下开启线程
        t = Thread(target=work)
        t.start()
        print(threading.current_thread().getName())
        print(threading.current_thread())  # 主线程
        print(threading.enumerate())  # 连同主线程在内有两个运行的线程
        print(threading.active_count())
        print('主线程/主进程')
    
    
    
    MainThread
    <_MainThread(MainThread, started 8504)>
    [<_MainThread(MainThread, started 8504)>, <Thread(Thread-1, started 4944)>]
    2
    主线程/主进程
    Thread-1
    

    守护线程

    无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁

    需要强调的是:运行完毕并非终止运行

    1. 对主进程来说,运行完毕指的是主进程代码运行完毕
    2. 对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕

    怎么理解呢?

    1. 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束
    2. 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
    from threading import Thread
    import time
    
    
    def sayhi(name):
        time.sleep(2)
        print('%s say hello' % name)
    
    
    if __name__ == '__main__':
        t = Thread(target=sayhi, args=('egon',))
        t.setDaemon(True)  # 必须在t.start()之前设置
        t.start()
        print('主线程')
        print(t.is_alive())
        
    
    主线程
    True
    

    主线程代码执行完毕,也要等子线程执行完,才算执行完


    *****
    *****
  • 相关阅读:
    pip 的简单安装与基本使用
    macOS(OS X)安装与配置 Homebrew
    命令行媒体处理工具 FFmpeg
    修正 FreeBSD 字体锯齿问题
    在 Linux 环境直接复移动硬盘上的 GRUB
    命令行视频下载工具 youget 和 youtubedl
    20不努力,30做助理(转载)
    树、森林和二叉树的转换
    百度地图和solr展示资源和附近等功能的实现 二
    加密Web项目中数据库配置文件中的密码
  • 原文地址:https://www.cnblogs.com/jevious/p/11404875.html
Copyright © 2011-2022 走看看