继承式多线程

1、定义

继承式多线程是自己自定义类,去继承theading.Tread这个类,通过类实例.start()启动,去执行run方法中的代码。

import threading
import time class MyThread(threading.Thread): # 继承threading.Thread
"""继承式多线程"""
def __init__(self, n):
threading.Thread.__init__(self) # 也可以写成这样super(MyThread,self).__init__()
self.n = n def run(self): # 重写run方法
"""这个方法不能叫别的名字,只能叫run方法"""
print("run", self.n)
time.sleep(2) t1 = MyThread("t1") # 实例化
t2 = MyThread("t2") t1.start() # 启动一个多线程
t2.start()

2、通过for循环来启动线程

上面的例子只启动了一个2个线程,还是用那种古老的方式t1,t2。要是一下子起10个或者100个线程,这种方式就不适用了,其实可以在启动线程的时候,把它加到循环里面去,并且来计算一下它的时间:

这里设置成启动5个线程,并且计算一下时间。这里有个疑问,为什么不启动1000个线程或者更多一点的线程?这是因为:计算机是4核的,它能干的事情,就是4个任务。启动的线程越多,就代表着要在这个很多线程之间进行上下文切换。相当于教室里有一本书,某个人只看了半页,因为cpu要确保每个人都能执行,也就是这本是要确保教室每个同学都能看到,那就相当于每个人看书的时间非常少。也就是说某个同学刚刚把这本书拿过来,一下子又被第二个人,第三个人拿走了。所以就导致所有的人都慢了,所以说如果线程启动1000,启动10000就没有意义了,导致机器越来越慢,所以要适当设置

import threading,time

def run(n):   #这边的run方法的名字是自行定义的,跟继承式多线程不一样,那个是强制的
print("task:",n)
time.sleep(2)
print("task done",n) start_time = time.time() #开始时间
for i in range(5): #一次性启动5个线程
t = threading.Thread(target=run,args=("t-{0}".format(i),))
t.start() print("--------all thead has finished")
print("cost:",time.time()-start_time) #计算总耗时 #执行结果
task: t-0
task: t-1
task: t-2
task: t-3
task: t-4
--------all thead has finished
cost: 0.00096893310546875
task done t-1
task done t-2
task done t-0
task done t-4
task done t-3

从上面的程序发现,就是我主线程没有等其他的子线程执行完毕,就直接往下执行了,这是为什么呢?而且这个计算的时间根本不是我们想要的时间,中间的sleep 2秒哪里去了?

其实一个程序至少有一个线程,那先往下走的,没有等的就是主线程,主线程启动了子线程之后,子线程就是独立的,跟主线程就没有关系了。主线程和它启动的子线程是并行关系,这就解释了为什么我的主线程启动子线程之后,没有等子线程,而继续往下走了。所以计算不出来线程总共耗时时间,因为程序已经不是串行的了。程序本身就是一个线程,就是主线程。如果要想测试这五个线程总共花了多长时间,就需要用到线程的内置韩式join()

3、join设置等待线程执行结果

 3.1、通过设置在主线程里去等待子线程的执行结果,这里join()相当于wait的意思

import threading
import time class MyThead(threading.Thread):
"继承式多线程"
def __init__(self,n):
super(MyThead,self).__init__()
self.n = n def run(self):
"这个方法不能叫别的名字,只能叫run方法"
print("runinit task",self.n)
time.sleep(2) t1 = MyThead("t1")
t2 = MyThead("t2") t1.start()
t1.join() #等待t1线程的执行结果,相当于于其他语言里面的 t1.wait()
t2.start()

注:

  1. t1.join()    等待第一个线程的执行结果,这个结果在没有返回之前,程序是不往下走的。所以这个程序变成串行的了。
  2. t2.start()   这个后面没有写 join() 这个方法,但是程序在退出之前,它肯定要确保线程都执行完毕,所以它就默认就有一个join()。

3.2、实现并发效果

上面虽然有想要的结果,却失去了并行的效果。如果想要的是线程依然是并行效果,就需要更换join()的位置了

流程图:

代码:

import threading
import time class MyThread(threading.Thread): # 继承threading.Thread
"""继承式多线程"""
def __init__(self, n, sleep_time): # 增加时间属性
threading.Thread.__init__(self) # 也可以写成这样super(MyThread,self).__init__()
self.n = n
self.sleep_time = sleep_time def run(self): # 重写run方法
print("run task", self.n)
time.sleep(self.sleep_time) # 每个线程可以传入不不同的时间
print("task done,", self.n) t1 = MyThread("t1", 2) # 实例化
t2 = MyThread("t2", 4) t1.start() # 启动一个多线程
t2.start() t1.join() # 把t1.join()放在线程启动之后
print("main thread.....") #执行结果
run task t1
run task t2
task done, t1
main thread.....
task done, t2

注:t1.join()    这边只等t1的结果,然后主线程继续往下走,因为t2需要等4秒,所以,最后打出来的是t2的执行结果。t1的结果到了,就立刻算结果。这边只计算了t1的结果,没有t2的结果

3.3 、计算多个线程的执行时间

重新改进一下第二点 “通过for循环来启动线程” 里面的代码,来计算一下10个线程启动执行的时间

import threading
import time def run(n): # 这边的run方法的名字是自行定义的,跟继承式多线程不一样,那个是强制的
print("task:", n)
time.sleep(2)
print("task done", n) start_time = time.time() # 开始时间
t_obj = [] # 存放子线程实例
for i in range(10): # 一次性启动10个线程
t = threading.Thread(target=run, args=("t-{0}".format(i),))
t.start()
t_obj.append(t) # 为了不阻塞后面线程的启动,不在这里join,先放到一个列表中 for t in t_obj: # 循环线程实例列表,等待所有线程执行完毕
t.join() print("--------all thread has finished")
print("cost:", time.time() - start_time) # 计算总耗时 # 执行结果
task: t-0
task: t-1
task: t-2
task: t-3
task: t-4
task: t-5
task: t-6
task: t-7
task: t-8
task: t-9
task done t-2
task done t-1
task done t-0
task done t-3
task done t-4
task done t-5
task done t-6
task done t-9
task done t-8
task done t-7
--------all thread has finished
cost: 2.0067291259765625

这样主线程没有等其他的子线程执行完毕,才继续往下执行,就能测试出10个线程执行的总共耗时。

守护线程

上面的例子在不加join的时候,主线程和子线程完全是并行的,没有了依赖关系,主线程执行了,子线程也执行了。但是加了join之后,主线程依赖子线程执行完毕才往下走。

守护进程:

只要主线程执行完毕,它不管子线程有没有执行完毕。就退出了。现在就可以把所有的子线程变成守护线程。变成守护线程之后,主程序就不会等子线程结束载退出了。说白了,设置一个主人,在设置几个仆人,这几个仆人都是为主人服务的。可以帮主人做很多事情,一个主人(主线程)可以有多个仆人(守护线程),服务的前提是,主线程必须存在,如果主线程不存在,则守护进程也没了。那守护进程是干嘛的呢?可以管理一些资源,打开一些文件,监听一些端口,监听一些资源,把一些垃圾资源回收,可以干很多事情,可以随便定义。

1、守护线程设置

用setDaemon(True)来设置守护线程

import threading
import time def run(n):
print("task:", n)
time.sleep(2)
print("task done", n) start_time = time.time()
for i in range(5):
t = threading.Thread(target=run,args=("t-{0}".format(i),))
t.setDaemon(True) # Daemon意思是守护进程,这边是把当前线程设置为守护线程
t.start() print("--------all thread has finished")
print("cost:", time.time() - start_time) #执行结果
task: t-0
task: t-1
task: t-2
task: t-3
task: t-4
--------all thread has finished
cost: 0.0010023117065429688

注:守护进程一定要在start之前设置,start之后就不能设置了,之后设置会报错,所以必须在start之前设置

2、使用场景

比如写一个socket_server,每一个链接过来,socket_server就会给这个链接分配一个新的线程。如果我手动的把socket_server停掉。那这种情况你必须手动停掉服务,那它就要down了,这种情况下还要等线程结束吗?就不用等线程结束了,它自己就直接结束了。这样,是不是就可以把每个socket线程设置一个守护线程,主线程一旦down掉,就全部退出。

3、知识点补充

查看当前线程和统计活动线程个数,用theading.current_thead()查看当前线程;用theading.active_count()来统计当前活动的线程数,线程个数=子线程数+主线程数

import threading,time

def run(n):
print("task:",n)
time.sleep(2)
print("task done",n,threading.current_thread()) #查看每个子线程 start_time = time.time()
for i in range(5):
t = threading.Thread(target=run,args=("t-{0}".format(i),))
t.start() print("--------all thead has finished",threading.current_thread(),threading.active_count())#查看主线程和当前活动的所有线程数
print("cost:",time.time()-start_time) #执行结果
task: t-0
task: t-1
task: t-2
task: t-3
task: t-4
--------all thead has finished <_MainThread(MainThread, started 3840)> 6
cost: 0.0019359588623046875
task done t-0 <Thread(Thread-1, started 11536)>
task done t-3 <Thread(Thread-4, started 10480)>
task done t-2 <Thread(Thread-3, started 11008)>
task done t-4 <Thread(Thread-5, started 5088)>
task done t-1 <Thread(Thread-2, started 2464)>

  

【python】-- 继承式多线程、守护线程的更多相关文章

  1. python 并发编程 多线程 守护线程

    做完工作这个进程就应该被销毁 单线程情况: 一个进程 ,默认有一个主线程 ,这个主线程执行完代码后 ,就应该自动销毁.然后进程也销毁. 多线程情况: 主线程代表进程结束 一个进程可以开多个线程,默认开 ...

  2. python 继承式多线程

    Thread是线程类,有两种使用方法,直接传入要运行的方法或从Thread继承并覆盖run(): Thread继承 import threading import time class MyThrea ...

  3. Python多线程-守护线程

    守护线程:守护着非守护线程,守护线程和非守护线程同时运行,当非守护线程运行结束后,无论守护线程有没有运行完,脚本都会停止运行 首先看一段普通的多线程实例 # -*- coding:utf-8 -*- ...

  4. python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  5. java线程 - 多线程 - 守护线程

    1.多线程执行者/处理类 都是Runnable的实现类(如自定义类实现Runnable 或 java原生的Thread.FutureTask),但最后都必须封装成Thread线程类由Thread.st ...

  6. 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁

    一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...

  7. 多线程-守护线程-setDaemon

    1 package multithread4; 2 /* 3 * 停止线程: 4 * 1,stop方法. 5 * 6 * 2,run方法结束. 7 * 8 * 怎么控制线程的任务结束呢? 9 * 任务 ...

  8. python 并发编程 多线程 开启线程的两种方式

    一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性 二 开启线程的两种方式 第一种 每造一个进程,默认有一个线程,就是 ...

  9. python 并发编程 多线程 目录

    线程理论 python 并发编程 多线程 开启线程的两种方式 python 并发编程 多线程与多进程的区别 python 并发编程 多线程 Thread对象的其他属性或方法 python 并发编程 多 ...

随机推荐

  1. autocomplete属性在谷歌浏览器不起作用

    大家都知道autocomplete属性是表单字段中的HTML5新属性,该属性有两种状态值,分别为"on" 和 "off",该属性可省略:省略属性值后默认值为&q ...

  2. Sending SMS And Dialing Numbers without User Consent(Context is not needed)

    Sending SMS And Dialing Numbers without User Consent Sending SMS does not require context or user in ...

  3. Efficiently traversing InnoDB B+Trees with the page directory--slot

    Efficientlytraversing InnoDB B+Trees with the page directory 1.the purpose of the page directory As ...

  4. tab menu

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 使用LBS(地理位置)

    一.使用之前的简单封装的OkHttpUtil http://www.cnblogs.com/itfenqing/p/6758909.html 二.关键代码: public class MainActi ...

  6. Fragment生命周期和Activity生命周期的关系

    Fragment生命周期: 重点回调函数: 1. onAttach()当碎片和活动建立关联的时候调用.2. onCreateView()为碎片创建视图(加载布局)时调用.3. onActivityCr ...

  7. [转]php-fpm配置具体解释

    [转]php-fpm配置具体解释 php-fpm具体解释 原文链接:http://php-fpm.anight.org/wiki:http://www.php-fpm.com/翻译:http://sy ...

  8. <context:annotation-config/>、<context:component-scan/>

    在基于主机方式配置Spring的配置文件中,你可能会见到<context:annotation-config/>这样一条配置,他的作用是式地向 Spring 容器注册 AutowiredA ...

  9. shell去掉后缀方法

    #!/bin/bash olddir=/home/img/luimg newdir=/home/img/luimg/thumb while read line do if [ -f $olddir${ ...

  10. 清华EMBA课程系列思考之三 -- 中国经济与金融

    清华EMBA的第三次课,大家都已经渐渐了解了课程系列的基本节奏,也逐步适应了思考的基本思路,本次课程涉及到的全部内容都非常专业.闲话少述,直入主题了. 李稻葵教授部分: -- 清华大学经济管理学院弗里 ...