Python 多任务编程 - 多线程
文章目录
1. 线程的介绍
1.1 实现多任务的另一种方式
- 在python 中,想要实现多任务还可以使用所线程来完成。
1.2 为什么使用多线程?
- 进程是分配资源的最小单位,一旦创建一个进程就会分配一定的资源,就像两个人聊QQ就需要打开两个QQ软件一样是比较浪费资源的。
- 线程是 程序执行的最小单位,实际上进程只负责分配资源,而利用这些资源执行程序的是线程,也就是说进程是线程的容器,一个进程中最少有一个线程来负责执行程序,同时线程自己不拥有系统资源,只需要一点儿在运行中必不可少的资源,但可与它同属一个进程的其他线程共享进程所拥有的全部资源,这就像通过一个QQ软件(一个进程)打开两个窗口(两个线程)跟两个人聊天一样,实现多任务的同时也节省了资源。
1.3 多线程的作用
同样需求使用多线程完成
def func_a():
print("任务A")
def func_b():
print("任务B")
func_a()
func_b()
2. 多线程完成多任务
2.1 线程的创建步骤
-
- 导入线程模块
import threading
-
- 通过线程类创建线程对象
线程对象 = threading.Thread(target=任务名)
-
- 启动线程执行任务
线程对象.start()
2.2 通过线程类创建线程对象
线程对象 = threading.Tread(target=任务名)
参数名 | 说明 |
---|---|
target | 执行的目标任务名,这里指的是函数名(方法名) |
name | 线程名,一般不用设置 |
group | 线程组,目前只能用None |
2.3 线程创建与启动代码
# 创建子线程
sing_thread = threading.Thread(target=sing)
# 创建子线程
dance_thread = threading.Thread(target=dance)
# 启动线程
sing_thread.start()
dance_thread.start()
- 示例
import time
import threading
def sing():
for i in range(3):
print("唱歌")
time.sleep(1)
def dance():
for i in range(3):
print("跳舞")
time.sleep(1)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing)
dance_thread = threading.Thread(target=dance)
sing_thread.start()
dance_thread.start()
3. 线程执行带有参数的任务
3.1 线程执行带有参数的任务
参数名 | 说明 |
---|---|
args | 以元组方式传参 |
Kwargs | 以字典方式传参 |
3.2 args 参数的使用
- target:线程执行的函数名
- args: 表示以元组方式给函数传参
sing_thread = threading_Thread(target=sing, args=(3,))
sing_thread.start()
3.3 Kwargs 参数的使用
# target: 线程执行的函数名
# kwargs: 表示以字典的方式给函数传参
dance_thread = threading.Thread(target=dance, kwargs={"count": 3})
dance_thread.start()
- 示例
import time
import threading
def sing(num, name):
for i in range(num):
print(name, ": 唱歌")
time.sleep(1)
def dance(count):
for i in range(count):
print("跳舞")
time.sleep(1)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing, args=(3, "xiaoming"))
dance_thread = threading.Thread(target=dance, kwargs={"count": 2})
sing_thread.start()
dance_thread.start()
-
【注】:
元组方式传参:元组方式传参一定要和参数的 顺序保持一致 。
字典方式传参:字典方式传参字典中的 key 一定要和 参数名保持一致 。
4. 主线程和子线程的结束顺序
-
对比进程
主线程会等待所有的子线程执行结束后主线程再结束。
-
示例
import time
import threading
def work():
for i in range(10):
print("工作")
time.sleep(0.2)
if __name__ == '__main__':
sub_thread = threading.Thread(target=work)
sub_thread.start()
# 主线程等待 1s, 后结束
time.sleep(1)
print("主线程结束了……")
# 主线程会等待所有的子线程执行结束后主线程再结束。
4.1 设置守护主线程
要想主线程不等待子线程执行完成可以设置守护主线程。
# 设置守护主线程方式1,daemon=True 守护主线程
work_thread = threading.Thread(target=work, daemon=True)
# 设置守护主线程方式2
work_thread.daemon = True
work_thread.start()
# 主线程延迟 1s
time.sleep(1)
print("over")
- 示例
- 方式1
import time
import threading
def work():
for i in range(10):
print("工作")
time.sleep(0.2)
if __name__ == '__main__':
# sub_thread = threading.Thread(target=work)
# sub_thread.start()
# 设置守护主线程方式1,daemon=True 守护主线程
sub_thread = threading.Thread(target=work, daemon=True)
sub_thread.start()
# # 设置守护主线程方式2
# sub_thread = threading.Thread(target=work)
# sub_thread.daemon = True
# sub_thread.start()
# 主线程等待 1s, 后结束
time.sleep(1)
print("主线程结束了……")
# 主线程会等待所有的子线程执行结束后主线程再结束。
- 方式2
import time
import threading
def work():
for i in range(10):
print("工作")
time.sleep(0.2)
if __name__ == '__main__':
# sub_thread = threading.Thread(target=work)
# sub_thread.start()
# # 设置守护主线程方式1,daemon=True 守护主线程
# sub_thread = threading.Thread(target=work, daemon=True)
# sub_thread.start()
# 设置守护主线程方式2
sub_thread = threading.Thread(target=work)
sub_thread.daemon = True
sub_thread.start()
# 主线程等待 1s, 后结束
time.sleep(1)
print("主线程结束了……")
# 主线程会等待所有的子线程执行结束后主线程再结束。
注:’ 线程对象.setDaemon(True) ’ 此方式自 3.10 起已弃用,可以使用 ’ 线程对象.daemon = True ’ 设置。
5. 线程间的执行顺序
线程之间的执行是无序的,是由 CPU调度决定某个线程先执行的 。
5.1 线程之间执行是无序的
for i in range(5):
sub_thread = threading.Thread(target=task)
sub_thread.start()
5.2 获取当前的线程信息
# 通过 current_thread 方法获取线程对象
current_thread = threading.current_thread()
# 通过 current_thread 对象可以知道线程的相关信息,例如被创建的顺序
print(current_thread)
- 实例
import time
import threading
def task():
time.sleep(1)
# 通过 current_thread 方法获取线程对象
current_thread = threading.current_thread()
# 通过 current_thread 对象可以知道线程的相关信息,例如被创建的顺序
print(current_thread)
if __name__ == '__main__':
for i in range(5):
sub_thread = threading.Thread(target=task)
sub_thread.start()
# 结论:多线程之间执行是无序,由于 cpu 调度。
6. 进程和线程对比
6.1 关系对比
-
- 线程是依附在进程里面的,没有进程就没有线程。
-
- 一个进程默认提供一条线程,进程可以创建多个线程。
6.2 区别对比
-
- 创建进程的资源开销要比创建线程的资源开销要大。
-
- 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位。
-
- 线程不能够独立执行,必须依存在进程中。
6.3 优缺点对比
-
- 进程优缺点:
- 优点:可以用多核
- 缺点:资源开销大
-
- 线程优缺点:
- 优点:资源开销小
- 缺点:不能使用多核