【Python基础】线程
2023-12-15 11:51:04
线程与进程的区别与联系
- 线程是可以被计算机
CPU
调度的最小单元 - 进程是计算机分配资源(
CPU
、内存等)的最小单元 - 一个进程中至少有一个线程,同一个进程中的线程共享进程中的资源
同步任务
- 我们在此之前编写的代码都是同步代码,代码从上到下按顺序执行,如果前一个任务没有完成,那么不能运行之后的任务
示例
import time
def work_1():
print('任务1...')
time.sleep(2)
def work_2():
print('任务2...')
time.sleep(2)
start = time.time()
work_1()
work_2()
end = time.time()
print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 4.020084857940674 s
- 可以看到整个程序用时
4
4
4秒,
work_2()
需要等待work_1()
运行结束后才能运行
并发任务
- 使用线程来运行上面的代码,能够优化运行时间
示例
import time
import threading
def work_1():
print('任务1...')
time.sleep(2)
def work_2():
print('任务2...')
time.sleep(2)
# 通过 Thread 类创建线程对象, 并使用 target 绑定线程对象要运行的任务
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)
# 运行线程
start = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()
print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 2.0165793895721436 s
-
可以看到整个程序用时 2 2 2秒,
work_1()
和work_2
并发运行 -
下面的示例可以看到
CPU
调度线程时的“随机性”
import time
import threading
def work_1():
for i in range(5):
print('任务1...')
time.sleep(2)
def work_2():
for i in range(5):
print('任务2...')
time.sleep(2)
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)
t1.start()
t2.start()
任务1...
任务2...
任务2...任务1...
任务1...任务2...
任务2...
任务1...
任务2...
任务1...
- 可以看到任务
1
1
1和任务
2
2
2的调度顺序是我们无法确定的,是由
CPU
的调度算法决定的
线程方法
- 在学习线程方法之前,我们需要知道
Python
程序是如何被运行的- 一个
Python
文件被解释器运行时会在操作系统中创建一个进程 - 然后该进程会创建一个线程来运行文件中的代码,这个程序最初创建的线程称为主线程
- 当主线程执行到
t = threading.Thread()
时会创建一个新的线程,称为子线程 - 当前进程中的主线程与子线程由
CPU
进行调度,并发地运行,具体调度哪个线程由操作系统的调度算法决定 - 子线程在运行时,主线程不会等待子线程,而是继续向下执行,直到执行到文件末尾没有代码时,主线程会等待子线程运行结束后再退出
- 一个
thread_object.start()
-
t = threading.Thread()
只是创建了一个线程,并不会执行线程代码 -
t.start()
使线程t
达到就绪态,等待CPU
进行调度,具体何时调度由CPU
决定 -
以上面的并发任务的代码为例,先注释掉
t1.start()
和t2.start()
import time
import threading
def work_1():
print('任务1...')
time.sleep(2)
def work_2():
print('任务2...')
time.sleep(2)
# 通过 Thread 类创建线程对象, 并使用 target 绑定线程对象要运行的任务
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)
# 运行线程
start = time.time()
t1.start()
t2.start()
# t1.join()
# t2.join()
end = time.time()
print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 0.0009987354278564453 s
- 可以看到主线程没有等待子线程,而是继续向下执行
- 当执行到
end = time.time()
时,此时end
记录的时间是主线程运行到这行代码的时间 - 之后运行
print(f'总共用时: {end - start} s')
,输出时间0.0009987354278564453 s
,此时执行到了文件末尾没有其他代码,主线程会等待子线程运行结束后再退出 - 为了能正确记录线程运行的时间,我们需要让主线程等待子线程
thread_object.join()
t.join()
使主线程等待子线程,子线程任务执行结束后主线程再继续向下执行- 仍然以上面的并发任务的代码为例,取消注释
t1.start()
和t2.start()
import time
import threading
def work_1():
print('任务1...')
time.sleep(2)
def work_2():
print('任务2...')
time.sleep(2)
# 通过 Thread 类创建线程对象, 并使用 target 绑定线程对象要运行的任务
t1 = threading.Thread(target=work_1)
t2 = threading.Thread(target=work_2)
# 运行线程
start = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()
print(f'总共用时: {end - start} s')
任务1...
任务2...
总共用时: 2.008962392807007 s
- 可以看到主线程等待子线程运行结束后才继续向下执行,正确记录了子线程运行的时间
thread_object.setDaemon()
- 设置守护线程,需要在线程启动之前进行设置
- 如果一个线程是守护线程,那么主线程运行结束后不论子线程任务是否结束都会自动退出
- 没有设置守护线程的情况
import time
import threading
def work():
for i in range(5):
print(i)
time.sleep(1)
t = threading.Thread(target=work)
# t.setDaemon(True)
t.start()
print('主线程即将退出...')
0
主线程即将退出...
1
2
3
4
- 设置守护线程的情况
import time
import threading
def work():
for i in range(5):
print(i)
time.sleep(1)
t = threading.Thread(target=work)
t.setDaemon(True)
t.start()
print('主线程即将退出...')
0
主线程即将退出...
- 可以看到并没有继续输出 1 1 1、 2 2 2、 3 3 3、 4 4 4,主线程就退出了
thread_object.current_thread()
- 获取当前线程对象的引用
- 可以用来获取线程名称
import threading
def work():
name = threading.current_thread().name # getName()
print(name)
for i in range(5):
t = threading.Thread(target=work)
t.name = f'线程-{i}' # setName(f'线程-{i}')
t.start()
文章来源:https://blog.csdn.net/from__2023_11_28/article/details/135012593
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!