05-6 万字长文:实现多线程(中)

05-6 万字长文:实现多线程(中)

5.1 Thread 直接创建子线程

5.1.1 非守护线程

复杂的操作之前需要一个简单的示例开始:

# !/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 就已经结束了。

这种不会随着主线程结束而销毁的,这种线程它叫做:非守护线程

  1. 主线程会跳过创建的线程继续执行;
  2. 直到创建线程运行完毕;
  3. 程序结束;

既然,有非守护线程。那就还有守护线程。不要急,我再举个非守护线程的例子。

首先,我们可以使用 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

这样,主线程必须等待子线程都运行结束,主线程才继续运行并结束。

5.2 继承 Thread 类创建子线程

另外,我们也可以通过继承 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

可以看到,两种实现方式,其运行效果是相同的。

05-6 万字长文:实现多线程(中)05-6 万字长文:实现多线程(中)05-6 万字长文:实现多线程(中)

 

上一篇:python 线程 实现多任务


下一篇:并发编程 五 - 死锁