day9-继承式多线程

概述

前面通过实验,我们知道了线程的启动方式——直接调用,下面还有一种调用方式——通过类进行调用(继承式调用)

继承式多线程

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

    #在类里面必须要run方法名字,不能使用别的
    def run(self):  # 重写run方法
        print("running task:",self.n)
        time.sleep(3)


if __name__ == '__main__':
    t1 = MyThread(1)  #生成一个线程实例
    t2 = MyThread(2)  #生成另一个线程实例
    t1.start()  #启动线程
    t2.start()  #启动另一个线程

#运行输出

running task: 1
running task: 2

Process finished with exit code 0

解析:继承式多线程是先定义一个类,再继承threading.Thread。这就是使用类去启动线程。

我们之前只是启动了2个线程,如果我们想一次启动50个线程,那么如何启动呢?那么加入循环就可以了,接着我们来看看多线程

启动多线程

我们这里为了方便实验,就启动10个线程吧,暂时不启动那么多,并且计算一下时间。有人会说,为什么不启动1000个线程或者更多一点的线程。这边注意了:如果你的计算机是4核的,它能干的事情,就是4个任务。你启动的线程越多,就代表着要在多个线程之间进行上下文切换。相当于我有一本书,我还没看半页,因为cpu要确保每个人都能执行。也就是说我一本说我要确保60个人都能看到,那就相当于每个人执行的时间非常少。我把这本说拿过来,一下子又被第二个人,第三个人拿走了。所以就导致所有的人都慢了,所以说启动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-%s" %i,))
    t.start()

print("--------all theads has been finished")
print("cost:", time.time() - start_time)  # 计算总耗时

#运行输出

task: t-0
task: t-1
task: t-2
task: t-3
task: t-4
--------all theads has been finished
cost: 0.0008099079132080078
task done t-1
task done t-2
task done t-4
task done t-3
task done t-0

Process finished with exit code 0

可以看到,启动主程序(主线程)之后,没有等待其他子线程执行完毕,就直接继续往下执行了,这是为什么呢?我们中间明明隔了2s。

解析:一个程序至少有一个线程,那先往下走的,没有等的就是主线程,主线程启动了子线程之后,子线程就是独立的,跟主线程就没有关系了。主线程和它启动的子线程是并行关系,这就解释了为什么我的主线程启动子线程之后,没有等子线程执行完毕,而继续往下走了。所以我们计算不出来时间,因为程序已经不是串行的了。每次t.start()就启动一个新的子线程,子线程和主线程没有关系,相互是独立的(默认情况下主线程不会等待子线程执行完毕)。而且此程序本身就是一个线程,就是主线程,主线程启动了子线程。但是我就是想测试总共花了多长时间,怎么办?

尝试:使用join()方法

功能:去设置等待子线程的执行结果

说明:通过设置在主线程里去等待子线程的执行结果,子线程执行完def run()函数后,子线程就退出了,即代表执行结束了

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线程的执行结果
t2.start()
(隐含有个join())

#运行输出 

running task t1
(隔2s)               #等待t1的执行结果输出后再执行t2
running task t2

Process finished with exit code 0

解析:因为t2.start必须等待t1执行完毕后返回执行结果,t2才能执行,所以这个程序就变成串行的了,而t2后面没有join(),但是程序在运行结束退出之前,它要确保所有的线程都要执行完毕,所以最后默认就有一个join()。

产生的问题:我想要的效果明明就是线程依然是并行的,只不过是等所有的子线程执行完毕后,主线程再继续往下执行。

import threading, time

class MyThead(threading.Thread):

    def __init__(self, n, sleep_time):  # 增加时间参数
        super(MyThead, self).__init__()
        self.n = n
        self.sleep_time = sleep_time

    def run(self):
        print("running task", self.n)
        time.sleep(self.sleep_time)  # 每个线程可以传入不同的时间
        print("task done,", self.n)


t1 = MyThead("t1", 2)  # 线程t1传入2秒
t2 = MyThead("t2", 4)  # 线程t2传入4秒

t1.start()
t2.start()

t1.join()  # 把t1.join()放在2个线程启动之后,表明等待t1的执行结果
print("main thread.....")

#运行输出

running task t1
running task t2
task done, t1
main thread.....
task done, t2

Process finished with exit code 0

解析:t1.join()在这里是等待t1的执行结果,然后主程序(主线程)继续往下走,打印出main thread.......,t2此时正在执行,因为t2需要等4秒,所以,最后打印出来的是t2的执行结果。同时,这里有2个线程t1(等待2s),t2(等待4s),我想要2个线程全部执行完所要花的时间,应该在4s左右,如果在t1.join()后面直接打印时间(算出结果),那么也就是2s(此时t2还没执行完毕,而上面的程序中,没有写t2.join()等待t2的执行结果,所以只是2s,而不是4s。如果我们要把2个线程执行完后统一算结果,应该怎么办?还得等t2的执行结果,在t1.join()后面加上t2.join()。

回到启动多线程,计算一下启动5个进程的时间,所以要join() 5次(要等所有的线程全部执行完毕)

import threading, time


def run(n):
    print("task:", n)
    time.sleep(2)
    print("task done", n)


start_time = time.time()
t_objs = []  # 存放子线程实例
for i in range(5):
    t = threading.Thread(target=run, args=("t-%s" %i,))
    t.start()
    t_objs.append(t)  # 为了不阻塞后面线程的启动,不在这里join(),先把结果放到一个列表中

for t in t_objs:  # 循环线程实例列表,等待所有线程执行完毕
    t.join()

print("--------all thread has been finished")
print("cost:", time.time() - start_time)

#运行输出

task: t-0
task: t-1
task: t-2
task: t-3
task: t-4
task done t-1
task done t-2
task done t-0
task done t-3
task done t-4
--------all thread has been finished
cost: 2.0036489963531494

Process finished with exit code 0

解析:如果想要所有线程的执行结果的话,先创建一个临时列表,然后每循环一次把线程实例append到该列表中(为了不卡住下一个线程的启动)等到整个循环结束,再启动一个循环去获取结果。

注意:并不是第一个启动的线程就是主线程,主线程是程序本身,你是看不到的,程序本身也是一个线程。

posted @ 2017-10-26 21:47  Mr.hu  阅读(117)  评论(0编辑  收藏  举报