前言
本章节继续探讨threading@H_301_9@模块下关于锁的应用,注意。这一期很重要,依然是围绕着理论篇来讲,这一章节主要围绕理论篇中的线程切换做讲解,因此一定要有一些线程切换方面的知识。
线程安全
线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。
在聊线程安全之前,我还是决定拿之前的那个例子来描述它。
这里关于线程安全的代码测试我决定不用上面例举的这个例子,而是用多线程做密集型计算做演示,数值越大效果越明显:
import threading num = 0 def add(): global num for i in range(10000000): # 一千万次 num += 1 sub(): 一千万次 num -= 1 if __name__ == '__main__': t1 = threading.Thread(target=add,) t2 = threading.Thread(target=sub,) t1.start() t2.start() t1.join() t2.join() print("最终结果:",num) ==== 执行结果 ==== 三次采集 """ 最终结果: -1472151 最终结果: -2814372 最终结果: -5149396 """
一个加一千万次,一个减一千万次,按理来说最后的结果应该是0,但是为什么相差这么大?更加恐怖的是每次的结果都完全不一样呢?
其实这就是由于线程切换导致出的线程安全问题,因为我们不能精确的知道cpu会在什么时候进行线程的切换,那么如何控制它呢?我们就需要用到锁,其实通俗点来讲你可以这么认为他:
线程安全的目标:
线程之间共同操作一个资源 如何保持资源的同步性
因为线程的切换是由cpu控制的,所以我们要控制它的切换
线程安全的定义:
线程安全:多线程操作时,内部会让所有线程排队处理
线程不安全:我们需要一个机制来让所有线程进行排队处理
那么什么时候我们要考虑线程安全的问题呢?
多个线程对同一数据源进行写入操作时
Ps:在CPython的八大基本数据类型中,
list@H_301_9@和
dict@H_301_9@本身就是属于线程安全的容器。
锁的作用
锁就提供给我们能够自行操控线程切换的一种手段,而并非系统自带的切换机制进行切换。
Lock同步锁
方法大全
Lock同步(互斥)锁方法方法大全 | |
---|---|
方法/属性名称 | 功能描述 |
acquire(blocking=True,timeout=-1) | 上锁,在上锁状态中的代码块运行时不允许切换至其他线程运行。 |
release() | 解锁,解锁后系统可以切换至其他线程运行。 |
locked() | 如果获得了锁则返回真值。 |
Rlock递归锁方法方法大全 | |
---|---|
方法/属性名称 | 功能描述 |
acquire(blocking=True,timeout=-1) | 上锁,在上锁状态中的代码块运行时不允许切换至其他线程运行。如果已上锁,递归层数增加一层。 |
release() | 解锁,解锁后系统可以切换至其他线程运行。 |
Condition条件锁方法方法大全 | |
---|---|
方法/属性名称 | 功能描述 |
acquire(blocking=True,timeout=-1) | 上锁,在上锁状态中的代码块运行时不允许切换至其他线程运行。 |
release() | 解锁,解锁后系统可以切换至其他线程运行。 |
wait(timeout=None) | 等待唤醒,此时该线程是处于暂停运行状态,要么等待通知要么等待到超时时间后继续执行该线程。 |
wait_for(predicate,timeout=None) | 等待唤醒,直到返回了一个True@H_301_9@。 |
notify(n=1) | 通知唤醒,可以唤醒多个处于wait()@H_301_9@的线程,默认为1个。 |
notify_all() | 通知唤醒,唤醒所有处于wait()@H_301_9@的线程。 |
Event事件锁方法方法大全 | |
---|---|
方法/属性名称 | 功能描述 |
is_set() | 用来判断当前红绿灯(标志位)的状态,红灯为False@H_301_9@,绿灯为 |
set() | 通知所有处于红灯状态的线程开始运行,这相当于将标志位改为True@H_301_9@。 |
clear() | 将所有处于绿灯状态的线程暂停,这相当于将标志位改为False@H_301_9@。 |
wait(timeout=None) | 阻塞当前线程直到被放行,即等待红绿灯的通知,红灯停绿灯行。 |
Semaphore信号量锁方法方法大全 | |
---|---|
方法/属性名称 | 功能描述 |
acquire(blocking=True,timeout=-1) | 上锁,在上锁状态中的代码块运行时不允许切换至其他线程运行。 |
release() | 解锁,解锁后系统可以切换至其他线程运行。 |