复杂的操作之前需要一个简单的示例开始:
# !/usr/bin/python3 # -*- coding: utf-8 -*- # @Author:AI悦创 @DateTime :2019/10/25 9:50 @Function :功能 Development_tool :PyCharm # code is far away from bugs with the god animal protecting # I love animals. They taste delicious. import threading, time def start(): time.sleep(1) print(threading.current_thread().name) # 当前线程名称 print(threading.current_thread().is_alive()) # 当前线程状态 print(threading.current_thread().ident) # 当前线程的编号 print('start') # 要使用多线程哪个函数>>>target=函数,name=给这个多线程取个名字 # 如果你不起一个名字的话,那那它会自己去起一个名字的(pid)也就是个 ident # 类似声明 thread = threading.Thread(target=start,name='my first thread') # 每个线程写完你不start()的话,就类似只是声明 thread.start() print('stop') # 输出 start stop my first thread True 2968
如果有参数的话,我们就对多线程参数进行传参数。代码示例:
import threading, time def start(num): time.sleep(num) print(threading.current_thread().name) print(threading.current_thread().isAlive()) print(threading.current_thread().ident) print('start') thread = threading.Thread(target=start,name='my first thread', args=(1,)) thread.start() print('stop')
解析:
我认认真看一下我们的运行结果,
start |
---|
「stop」 |
「my first thread」 |
「True」 |
「2968」 |
我们会发现并不是按我们正常的逻辑执行这一系列的代码。
而是,先执行完 「start 然后就直接 stop」 然后才会执行我们函数的其他三项。
一个线程它就直接贯穿到底了。也就是先把我们主线程里面的代码运行完,然后才会运行它里面的代码。
我们的代码并不是当代码执行到 「thread.start()」 等它执行完再执行 「print('stop')」 。而是,我们线程执行到「thread.start()」 继续向下执行,同时再执行里面的代码(也就是**start()**函数里面的代码)。(不会卡在 thread.start() 那里) 「也不会随着主线程结束而结束」
❝因为,程序在执行到 「print('stop')」 之后就是主线程结束,而里面开的线程是我们自己开的。当我们主线程执行这个 stop 就已经结束了。
这种不会随着主线程结束而销毁的,这种线程它叫做:非守护线程
❞
既然,有非守护线程。那就还有守护线程。不要急,我再举个非守护线程的例子。
首先,我们可以使用 Thread 类来创建一个线程,创建时需要指定 target 参数为运行的方法名称,如果被调用的方法需要传入额外的参数,则可以通过 Thread 的 args 参数来指定。示例如下:
import threading, time def target(second): print(f'Threading {threading.current_thread().name} is runing') print(f'Threading {threading.current_thread().name} sleep {second}s') time.sleep(second) print(f'Threading {threading.current_thread().name} ended') print(f'Threading {threading.current_thread().name} is runing') for i in [1, 5]: t = threading.Thread(target=target, args=[i]) # t = threading.Thread(target=target, args=(i,)) t.start() print(f'Threading {threading.current_thread().name} is ended') # 输出 Threading MainThread is runing Threading Thread-1 is runing Threading Thread-1 sleep 1s Threading Thread-2 is runing Threading Thread-2 sleep 5s Threading MainThread is ended Threading Thread-1 ended Threading Thread-2 ended
在这里我们首先声明了一个方法,叫作 target,它接收一个参数为 second,通过方法的实现可以发现,这个方法其实就是执行了一个 time.sleep 休眠操作,second 参数就是休眠秒数,其前后都 print 了一些内容,其中线程的名字我们通过 threading.current_thread().name 来获取出来,如果是主线程的话,其值就是 MainThread,如果是子线程的话,其值就是 Thread-*。
然后我们通过 Thead 类新建了两个线程,target 参数就是刚才我们所定义的方法名,args 以列表的形式传递。两次循环中,这里 i 分别就是 1 和 5,这样两个线程就分别休眠 1 秒和 5 秒,声明完成之后,我们调用 start 方法即可开始线程的运行。
观察结果我们可以发现,这里一共产生了三个线程,分别是主线程 MainThread 和两个子线程 Thread-1、Thread-2。另外我们观察到,主线程首先运行结束,紧接着 Thread-1、Thread-2 才接连运行结束,分别间隔了 1 秒和 4 秒。这说明主线程并没有等待子线程运行完毕才结束运行,而是直接退出了,有点不符合常理。
如果我们想要主线程等待子线程运行完毕之后才退出,可以让每个子线程对象都调用下 join 方法,实现如下:
for i in [1, 5]: t = threading.Thread(target=target, args=[i]) t.start() t.join() # 输出 Threading MainThread is runing Threading Thread-1 is runing Threading Thread-1 sleep 1s Threading Thread-1 ended Threading Thread-2 is runing Threading Thread-2 sleep 5s Threading Thread-2 ended Threading MainThread is ended
这样,主线程必须等待子线程都运行结束,主线程才继续运行并结束。
另外,我们也可以通过继承 Thread 类的方式创建一个线程,该线程需要执行的方法写在类的 run 方法里面即可。上面的例子的等价改写为:
import threading, time class MyThread(threading.Thread): def __init__(self, second): threading.Thread.__init__(self) self.second = second def run(self): print(f'Threading {threading.current_thread().name} is runing') print(f'Threading {threading.current_thread().name} sleep {self.second}s') time.sleep(self.second) print(f'Threading {threading.current_thread().name} is ended') print(f'Threading {threading.current_thread().name} is runing') for i in [1, 5]: t = MyThread(i) t.start() t.join() print(f'Threading {threading.current_thread().name} is ended') # 输出 Threading MainThread is runing Threading Thread-1 is runing Threading Thread-1 sleep 1s Threading Thread-1 is ended Threading Thread-2 is runing Threading Thread-2 sleep 5s Threading Thread-2 is ended Threading MainThread is ended
可以看到,两种实现方式,其运行效果是相同的。