多线程
什么是线程
进程是操作系统可以调度已经进行资源分配的基本单位,是一个资源单位,其中包含了运行这个程序所需的资源
- 线程是操作系统可以运算调度的最小单位,是真正的执行单位,其包含在进程中, 一个线程就是一条固定的控制流程, 一个进程可以包含多个线程,同一进程中的线程共享进程内的资源
特点:系统会为每一个进程自动创建一条线程,称之为主线程, 后续通过代码开启的线程称之为子线程
进程和线程的对比
计算机是一个工厂,进程就是一个车间,线程就是车间内的流水线
Item | 进程 | 线程 |
---|---|---|
单位 | 资源单位 | 执行单位 |
创建开销 | 开销大 | 开销小 |
内存关系 | 内存相互隔离 | 共享进程内的所有资源 |
硬件资源 | 竞争关系 | 协作关系 |
层级关系 | 又上下层关系 | 平等关系 |
使用线程的优势
- 有多个任务要并发处理
- 当要并发处理的任务有很多的时,不能使用进程 进程资源开销太大 线程开销非常小 适用于任务数非常多的情况
线程的使用
-
方式一:直接实例化Thread类
from threading import Thread def task(): print("子线程 run") # 与进程不同之处1 不需要加判断 开启线程的代码放哪里都可以 t = Thread(target=task) t.start() print("over")
-
方式二:继承Thread类,覆盖run方法
class MyThread(Thread): def run(self): # 把要在子线中执行的代码放入run中 print("子 run") mt = MyThread() mt.start() print("over")
线程安全问题
只要并发访问了同一资源一定会产生安全问题,解决方案和多进程一致,就是给操作公共资源代码加锁
from threading import Thread,Lock
import time
a = 10
l = Lock()
def task():
global a
l.acquire()
temp = a
time.sleep(0.1)
a = temp - 1
l.release()
ts = []
for i in range(10):
t = Thread(target=task)
t.start()
ts.append(t)
for t in ts:
t.join()
print(a)
守护线程
一个线程a,设置为b的守护线程, a会随着b的结束而结束
默认情况下,主线程即使代码执行完毕,也会等待所有非守护线程完毕后程序才能结束 ,因为多个线程之间是协作关系
from threading import Thread
import time
# 妃子的一生
def task():
print("妃子 start")
time.sleep(5)
print("妃子 over")
def task2():
print("皇太后 start")
time.sleep(3)
print("皇太后 over")
# 皇帝的一生
print("主 start")
t = Thread(target=task) # 守护线程,主线程结束就结束
t.daemon = True
t.start()
t2 = Thread(target=task2) # 非守护线程,主线程会等待非守护线程结束后再结束
t2.start()
print("主 over")
"""结果
主 start
妃子start
皇太后 start
主over
皇太后 over
"""
线程中的常用属性和方法
from threading import Thread,currentThread,enumerate,activeCount
import time
# t = Thread()
# t.start()
# t.join()
# t.is_alive() # 判断线程是否开启
# t.isAlive() # 判断线程是否开启
# t.ident # 线程标识符 id
# t.daemon
# 获取当前线程对象
# print(currentThread())
# t = Thread(target=lambda :print(currentThread()))
# t.start()
t = Thread(target=lambda :time.sleep(1))
t.start()
t = Thread(target=lambda :time.sleep(1))
t.start()
t.join()
# 获取正在运行的所有线程对象 是一个列表
print(enumerate())
# 存活的线程数量
print(activeCount())