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

# 很显然把子线程设置为主线程的守护线程后,主线程一旦结束,程序就执行退出运行,不会再等待子线程运行。

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

时间: 2024-10-10 10:31:25

join和 Daemon守护线程的相关文章

Python多进程的Join和daemon(守护)的用法

join和daemon 下面仅以多进程为例: 知识点一: 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下(其实就是setDaemon(False)),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束,例子见下面一. 知识点二: 当我们使用setDaemon(True)方法,也就是设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行,可能出现的情况

Python多线程的创建,相关函数和守护线程的理解

一:多线程的创建 threading库创建线程有两种方式,函数式和继承式    1)函数式 def func(): print 'Starting' print 'Ending' t=threading.Thread(name='func',target=func) t.start() 2)继承式 class ThreadClass(threading.Thread): def __init__(self, group = None, target = None, name = None, ar

Java中的守护线程和非守护线程(转载)

<什么是守护线程,什么是非守护线程> Java有两种Thread:“守护线程Daemon”(守护线程)与“用户线程User”(非守护线程). 用户线程:非守护线程包括常规的用户线程或诸如用于处理GUI事件的事件调度线程,Java虚拟机在它所有非守护线程已经离开后自动离开. 守护线程:守护线程则是用来服务用户线程的,比如说GC线程.如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去.(操作系统里面是没有所谓的守护线程的概念,只有守护进程一说,但是Java语言机制是构建在JVM

python全栈开发基础【第二十四篇】(利用threading模块开线程、join与守护线程、GIL与Lock)

一多线程的概念介绍 threading模块介绍 threading模块和multiprocessing模块在使用层面,有很大的相似性. 二.开启多线程的两种方式 创建线程的开销比创建进程的开销小,因而创建线程的速度快. #开启进程的第一种方式 from multiprocessing import Process from threading import Thread import os import time def work(): print('<%s> is running'%os.g

python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon)

前言 今天小编YOYO请xiaoming和xiaowang吃火锅,吃完火锅的时候会有以下三种场景: 场景一:小编(主)先吃完了,xiaoming(客)和xiaowang(客)还没吃完,这种场景会导致结账的人先走了,剩下两个小伙伴傻眼了... 场景二:小编(主)先吃完了,xiaoming和xiaowang还没吃饱,一起结账走人. 场景三:小编(主)先等xiaoming和xiaowang吃饱了,小编最后结账一起走人. 主线程与子线程 场景一:主线程已经结束了,子线程还在跑 1.我们把thread1.

Python之路(第四十二篇)线程相关的其他方法、join()、Thread类的start()和run()方法的区别、守护线程

一.线程相关的其他方法 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. ? threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程对象. # threading.enumerate(): 返回一个包含正在运行的线程的list.正在运行指线程启动后.结束前,不包括启动前和终止后的线程. # threading.activeCount(

守护线程以及要使用时注意的一点(Daemon Thread)

在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) Daemon的作用是为其他线程的运行提供便利服务,比如垃圾回收线程就是一个很称职的守护者.User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了. 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了. 值得一提的是,守护线程并非只有虚拟机内部提供

Java:多线程&lt;四&gt; Lock、停止线程、守护线程、join、优先级&amp;yield

Java1.5以后,Condition将Object监视器方法(wait, notify, notifyAll)分解成截然不同的对象,以便通过这些对象与任意Lock实现组合使用为每个对像提供多个等待set(wait-set).期中,Lock替代了synchronized方法和语句的使用,Condition替代了Objetc监视器方法和使用. 当线程处于冻结状态,就有可能线程就不会结束,interrupt用于清除线程的冻结状态.当没有指定的方式让冻结状态的线程恢复到运行状态时,这是需要对冻结状态进

Java 中的守护(Daemon)线程中finally代码块是否执行的问题

http://www.cnblogs.com/luochengor/archive/2011/08/11/2134818.html 这篇文章应该是Thinking in Java 中文版中的一段,关于线程-守护线程(Daemon Thread)的介绍 可能是我理解de不好,我对书对于daemon thread 中的finally是否执行的介绍有点迷糊了,故自己写个方法测试之后才搞明白. 就拿书中的例子做进一步说明.先来看下原文:不看我的罗嗦,可以直接看文章结尾的结论. import java.u