ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-06-12 18:03:56  阅读:172  来源: 互联网

标签:thread Thread 05 print threading 线程 字长 多线程 start


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

标签:thread,Thread,05,print,threading,线程,字长,多线程,start
来源: https://blog.51cto.com/aiyc/2899192

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有