多线程编程threading

操作系统能够调度和切换的最小单元实际上是线程。
对于IO操作来说,多线程和多进程性能差别不大。
有两种方法可以进行多线程编程。

1.使用多线程编程的两种方法

(1)直接实例化一个Thread对象

from threading import Thread
import time

def task1():
    print("task1开始执行")
    time.sleep(5)
    print("task1执行结束")

def task2():
    print("task2开始执行")
    time.sleep(3)
    print("task2结束执行")

if __name__ == "__main__":
    t1 = Thread(target=task1)
    t2 = Thread(target=task2)
    start_time = time.time()
    t1.start()
    t2.start()
    run_time = time.time() - start_time
    print("执行时间:%s"%run_time)

执行结果:
  task1开始执行
  task2开始执行
  执行时间:0.0009980201721191406
  task2结束执行
  task1执行结束

 

t1和t2属于并发执行,t1和t2开始之后,并不会等到执行完毕之后再执行下面的代码。
因为在t1和t2之外还有一个主线程,我们通过debug可以看的一清二楚。

在主线程结束之后,会等待其中的子线程全部执行完毕之后才会退出,不然就不会打印子线程的结果信息。
我们可以做一些设置:
  t1.setDaemon(True)

执行结果:
  task1开始执行
  task2开始执行
  执行时间:0.0009980201721191406
  task2开始执行
setDaemon的意思是,将t1设置为守护线程,当主线程结束之后,守护线程也会随之结束。

如果你希望一定要等待线程执行完成,可以适用join。

from threading import Thread
import time

def task1():
    print("task1开始执行")
    time.sleep(5)
    print("task1执行结束")

def task2():
    print("task2开始执行")
    time.sleep(3)
    print("task2结束执行")

if __name__ == "__main__":
    t1 = Thread(target=task1)
    t1.setDaemon(True)  #主线程不用等待t1执行完毕之后才退出,但是依然要等待t2执行完毕。
    t2 = Thread(target=task2)
    start_time = time.time()
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    run_time = time.time() - start_time
    print("执行时间:%s"%run_time)
    
执行结果:
    task1开始执行
    task2开始执行
    task2结束执行
    task1执行结束
    执行时间:5.0016233921051025

加入join之后,不管你是否设置了守护线程,都会等到线程执行结束,才会接着往下执行。

 

(2)直接继承Thread类,重写run方法

from threading import Thread
import time

class T1(Thread):
    def run(self):
        print("task1开始执行")
        time.sleep(5)
        print("task1执行结束")

class T2(Thread):
    def run(self):
        print("task2开始执行")
        time.sleep(3)
        print("task2结束执行")



if __name__ == "__main__":
    t1 = T1()
    t2 = T2()
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("主线程结束")

两种方式其实是一样的,一个是作为子类一个是作为对象,方法和属性基本相同。
同时我们也可以通过super调用父类的__init__方法。

在代码逻辑比较简单的时候,适用第一种方法没有什么毛病,如果逻辑比较复杂使用第二种方法当然更合适。
不管你要适用那种方法,你都是操作的一个对象,如果你想获取结果,当然应该把结果绑定到对象上去。

 

2.Thread中的方法一览

daemon:等于isDaemon
getName:获取线程名
ident:线程标识符
isAlive:查看线程的运行状态
isDaemon:是否是守护线程
is_alive
join:等待线程执行完毕
name:property属性,可以给线程设置name
run:线程的逻辑部分,一般会重写这个方法
setDaemon:设置守护线程
setName:设置线程名
start:开始执行线程

posted @ 2019-08-02 17:00  明王不动心  阅读(210)  评论(0编辑  收藏  举报