一、前言

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

  结果:

  

二、join 等待子线程完成

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# -*- 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(18)
        time.sleep(t_time)
        print(self.getName(), 'finished''I sleep %d seconds' % t_time)
 
 
if __name__ == '__main__':
 
    start_time = time.time()
    for in range(5):
        = MyThread(i)
        t.start()
        t.join()    # 添加join,阻塞主线程
    print('main thread finished.')
    print('cost: %s' % (time.time() - start_time))
 
# 注
# 如果对每个线程都加join,那么并发就没有了,实际上线程都是串行的
# 前一个线程执行完了,才会执行下一个线程
# 主线程最后运行完毕

  结果:

  2.1 计算并发运行时间

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

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

  结果:

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

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

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

三、守护线程setDaemon

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# -*- 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(18)
        time.sleep(t_time)
        print(self.getName(), 'finished''I sleep %d seconds' % t_time)
 
 
if __name__ == '__main__':
 
    start_time = time.time()
    for in range(5):
        = 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() 查看活跃线程数

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

  结果: 

1
2
3
4
5
6
7
8
9
10
11
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
 
# 很显然把子线程设置为主线程的守护线程后,主线程一旦结束,程序就执行退出运行,不会再等待子线程运行。

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

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

  1. (4)进程---daemon守护线程和join阻塞

    join ()方法:主线程A中,创建了子线程B,并且在主线程A中调用了B.join(),那么,主线程A会在调用的地方等待,直到子线程B完成操作后,才可以接着往下执行,那么在调用这个线程时可以使用被调用 ...

  2. python网络编程--线程join和Daemon(守护进程)

    一:什么情况下使用join join([timeout])调用join函数会使得主调线程阻塞,直到被调用线程运行结束或超时. 参数timeout是一个数值类型,用来表示超时时间,如果未提供该参数,那么 ...

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

    join和daemon 下面仅以多进程为例: 知识点一: 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下 ...

  4. java 多线程:Thread类常用方法:setPriority优先级、interrupt中断标记、suspend暂停与唤醒resume(已过时);daemon守护线程

    常用方法: boolean isAlive() 测试此线程是否存活. boolean isDaemon() 测试此线程是否为守护程序线程. static void sleep?(long millis ...

  5. Java Daemon 守护线程

    Java中可以通过Thread或ThreadGroup的setDaemon方法将线程设置为守护线程 当所有非守护线程退出后 守护线程将被杀死不在运行 .Net中可以通过设置IsBackground属性 ...

  6. 进程Process之join、daemon(守护)、terminate(关闭)、multiprocessing之锁、信号量和事件

    一.Process 参数介绍: 1 group参数未使用,值始终为None 2 target表示调用对象,即子进程要执行的任务 3 args表示调用对象的位置参数元组,args=(1,2,'a',) ...

  7. 进程Process之join、daemon(守护)、terminate(关闭)

    一.Process 参数介绍: 1 group参数未使用,值始终为None 2 target表示调用对象,即子进程要执行的任务 3 args表示调用对象的位置参数元组,args=(1,2,'a',) ...

  8. Daemon 守护线程(27-11)

    t2.setDaemon(True)不再等待里面的sleep(5). 当设成setDaemon(True)这个线程就不等了. 例子一: import threadingfrom time import ...

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

    <什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...

随机推荐

  1. java后台调用http请求

    1:代码   @Value("${sms.username}")  可以将sms.properties配置文件中的值注入到username //这种方式是将sms.properti ...

  2. Ubuntu 通过 Live CD 更新grub恢复引导Boot Menu

    工作需要更换主板,但是不想重装电脑. 怎么办呢? 其实并不需要重装电脑,只需要回复boot menu即可. 1. 首先用u盘制作一个ubuntu的live CD(请自行百度),然后通过u盘启动, 选择 ...

  3. 莫烦课程Batch Normalization 批标准化

    for i in range(N_HIDDEN): # build hidden layers and BN layers input_size = 1 if i == 0 else 10 fc = ...

  4. C# 去除文件非法字符名

    string resultFileName = MD5Encrypt(NavigateUrl).Replace("=",string.Empty) + ".txt&quo ...

  5. 含有ref out 参数 的方法反射 Emit 与 普通

    反射中很多朋友应该屡屡被带有ref out参数的方法折腾 当使用正常反射一个方法时候: 代码如下调用一个后期绑定方法MakeByRefType 就行了 MemberInfo test = typeof ...

  6. IP地址、域名、域名解析系统相关

    IP地址(Internet Protocol Address) 它来自TCP/IP协议,存在于其中的IP层,用于实现不同计算机之间的通信,类似于门牌号. 设计之处,IP地址是准备给地球上每一台计算机一 ...

  7. Python开发环境(1):Eclipse+PyDev插件

    电脑:小米笔记本电脑Pro 15.6寸(i5-8250U),操作系统:Windows 10,JDK版本:1.8.0_152(环境变量已配置) Step 1.下载Eclipse 根据我的CPU型号,选择 ...

  8. 【前端vue开发】vue子调父 $emit (把子组件的数据传给父组件)

    ps:App.vue 父组件 Hello.vue 子组件 <!--App.vue :--> <template> <div id="app"> ...

  9. MyBatis3-实现MyBatis分页

    此文章中的例子是沿用上一篇文章http://www.cnblogs.com/EasonJim/p/7055499.html的Spring MVC集成的例子改装的. MyBatis分页有以下方式实现: ...

  10. JAVA复习笔记之多线程并发

    前言:多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,还是值得深入研究一下 概念: 1 线程:进程中负责程序执行的执行单元线程本身依靠程序进行运行线程是程序中的顺序控制流,只能使用 ...