zoukankan      html  css  js  c++  java
  • join和 Daemon守护线程

    一、前言

      一个程序至少有一个主线程,主线程启动子线程后,它们之间并没有隶属关系。主线程和子线程执行是并行的,相互独立。主线程执行完毕后默认不等子线程执行结束就接着往下走了,如果有其他程序就会运行另外的程序,如果没有就等待子线程执行完成后结束程序。

    import threading
    import time
    import random
    
    
    class MyThread(threading.Thread):
    
        def __init__(self, n):
            super(MyThread, self).__init__()
            self.n = n
    
        def run(self):
            print('task %s is operating' % self.n)
            t_time = random.randint(1, 8)
            time.sleep(t_time)
           # getNname获取线程名称
            print(self.getName(), 'finished', 'I sleep %d seconds' % t_time)
    
    
    class Person(object):
    
        def __init__(self, name):
            self.name = name
    
        def get_info(self):
            # time.sleep(10)
            print('my name is %s.' % self.name)
    
    if __name__ == '__main__':
    
        start_time = time.time()
        for i in range(5):
            t = MyThread(i)
            t.start()
        # t.join()
        print('main thread finished.')
        print('*****执行另一个程序了******')
        p = Person('bigberg')
        p.get_info()
        print('*************************')
        print('cost: %s' % (time.time() - start_time))
    

      结果:

    # 线程开始执行
    
    task 0 is operating
    task 1 is operating
    task 2 is operating
    task 3 is operating
    task 4 is operating
    # 主线程执行完毕
    main thread finished.
    
    # 可以执行另一个程序了
    *****执行另一个程序了******
    my name is bigberg.
    *************************
    # 这里花费的时间是主线程的运行时间,显然没有计算子线程的时间
    cost: 0.0019881725311279297
    
    # 子线程在主线程结束后依然在运行
    Thread-3 finished I sleep 2 seconds
    Thread-5 finished I sleep 2 seconds
    Thread-2 finished I sleep 3 seconds
    Thread-4 finished I sleep 4 seconds
    Thread-1 finished I sleep 5 seconds
    
    # 所有子线程完毕后程序结束
    Process finished with exit code 0
    

      

    二、join 等待子线程完成

      如果在线程实例后加上join默认主线程是阻塞的,主线程会等待该子线程运行完成后在结束。

    # -*- coding: UTF-8 -*-
    
    import threading
    import time
    import random
    
    
    class MyThread(threading.Thread):
    
        def __init__(self, n):
            super(MyThread, self).__init__()
            self.n = n
    
        def run(self):
            print('task %s is operating' % self.n)
            t_time = random.randint(1, 8)
            time.sleep(t_time)
            print(self.getName(), 'finished', 'I sleep %d seconds' % t_time)
    
    
    if __name__ == '__main__':
    
        start_time = time.time()
        for i in range(5):
            t = MyThread(i)
            t.start()
            t.join()    # 添加join,阻塞主线程
        print('main thread finished.')
        print('cost: %s' % (time.time() - start_time))
    
    # 注
    # 如果对每个线程都加join,那么并发就没有了,实际上线程都是串行的
    # 前一个线程执行完了,才会执行下一个线程
    # 主线程最后运行完毕
    

      结果:

    task 0 is operating
    Thread-1 finished I sleep 2 seconds
    task 1 is operating
    Thread-2 finished I sleep 6 seconds
    task 2 is operating
    Thread-3 finished I sleep 4 seconds
    task 3 is operating
    Thread-4 finished I sleep 8 seconds
    task 4 is operating
    Thread-5 finished I sleep 5 seconds
    # 这里主线程已经是最后执行完毕的了
    main thread finished.
    
    # 消耗的时间也是每个线程的运行时间之和
    cost: 25.005265712738037
    

      2.1 计算并发运行时间

      如果不想计算出总的运行时间,而是所有线程的并发运行时间呢?就像上例中的那样,最长运行时间是8秒,那么所有线程都能在8秒内全部运行完毕。

      把t.join()单独移到for循环外面是不行的,因为这样并发运行总会在最后一个线程出阻塞。如下:  

    # -*- coding: UTF-8 -*-
    
    import threading
    import time
    import random
    
    
    class MyThread(threading.Thread):
    
        def __init__(self, n):
            super(MyThread, self).__init__()
            self.n = n
    
        def run(self):
            print('task %s is operating' % self.n)
            t_time = random.randint(1, 8)
            time.sleep(t_time)
            print(self.getName(), 'finished', 'I sleep %d seconds' % t_time)
    
    
    if __name__ == '__main__':
    
        start_time = time.time()
        for i in range(5):
            t = MyThread(i)
            t.start()
        t.join()    # 添加join,阻塞主线程
        print('main thread finished.')
        print('cost: %s' % (time.time() - start_time))
    

      结果:

    task 0 is operating
    task 1 is operating
    task 2 is operating
    task 3 is operating
    task 4 is operating
    Thread-1 finished I sleep 2 seconds
    Thread-3 finished I sleep 2 seconds
    Thread-5 finished I sleep 3 seconds
    # 其实是在线程5,也就是最后一个线程出阻塞的
    main thread finished.
    cost: 3.001293659210205
    Thread-2 finished I sleep 4 seconds
    Thread-4 finished I sleep 5 seconds
    

      正确的方法,定义一个空列表,获取所以的线程实例,for 循环阻塞所有的线程实例 

    # -*- coding: UTF-8 -*-
    
    import threading
    import time
    import random
    
    
    class MyThread(threading.Thread):
    
        def __init__(self, n):
            super(MyThread, self).__init__()
            self.n = n
    
        def run(self):
            print('task %s is operating' % self.n)
            t_time = random.randint(1, 8)
            time.sleep(t_time)
            print(self.getName(), 'finished', 'I sleep %d seconds' % t_time)
    
    
    if __name__ == '__main__':
        t_list = []
        start_time = time.time()
        for i in range(5):
            t = MyThread(i)
            t.start()
            t_list.append(t)
    
        for t in t_list:
            t.join()
        print('main thread finished.')
        print('cost: %s' % (time.time() - start_time))
    

      结果,事实上也符合我们刚才的推论,运行时间最长的线程所消耗的时间,就是总的并发时间 

    task 0 is operating
    task 1 is operating
    task 2 is operating
    task 3 is operating
    task 4 is operating
    Thread-3 finished I sleep 3 seconds
    Thread-5 finished I sleep 3 seconds
    Thread-2 finished I sleep 7 seconds
    Thread-1 finished I sleep 7 seconds
    Thread-4 finished I sleep 8 seconds
    main thread finished.
    cost: 8.001787185668945
    
    # 并发时间在8秒左右
    

      总结:主线程创建一个子线程后,如果子线程调用join()方法,主线程会在调用的地方等待,直到该子线程运行完成才会接着往下执行。

    三、守护线程setDaemon

      setDaemon()方法:在主线程中创建子线程,该子线程调用setDaemon方法后成为主线程的守护线程。这种情况下如果主线程执行结束,那么不管子线程是否完成,一并和主线程退出。这里基本和join()方法相反。此外,还有个要特别注意的:必须在start() 方法调用之前设置,如果不设置为守护线程,程序会被无限挂起。  

    # -*- coding: UTF-8 -*-
    
    import threading
    import time
    import random
    
    
    class MyThread(threading.Thread):
    
        def __init__(self, n):
            super(MyThread, self).__init__()
            self.n = n
    
        def run(self):
            print('task %s is operating' % self.n)
            t_time = random.randint(1, 8)
            time.sleep(t_time)
            print(self.getName(), 'finished', 'I sleep %d seconds' % t_time)
    
    
    if __name__ == '__main__':
    
        start_time = time.time()
        for i in range(5):
            t = MyThread(i)
            t.setDaemon(True)
            t.start()
        print('main thread finished.', threading.current_thread(), threading.active_count())
        print('cost: %s' % (time.time() - start_time))
    

      注:threading.current_thread()查看当前运行的线程

        threading.active_count() 查看活跃线程数

        线程数 =  主线程 + 子线程数

      结果: 

    task 0 is operating
    task 1 is operating
    task 2 is operating
    task 3 is operating
    task 4 is operating
    main thread finished. <_MainThread(MainThread, started 8656)> 6
    cost: 0.0009999275207519531
    
    Process finished with exit code 0
    
    # 很显然把子线程设置为主线程的守护线程后,主线程一旦结束,程序就执行退出运行,不会再等待子线程运行。
    

      注:如果程序中有其他非守护线程时,还是会等待非守护线程运行完毕,程序才会结束。

  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/bigberg/p/7815443.html
Copyright © 2011-2022 走看看