线程锁:
Lock :原始锁,目前可用的最低级的同步原语
Rlock :可重入锁
class threading.Lock
class threading.RLock
实例方法:
acquire(blocking=True, timeout=-1) 尝试锁定
release() :释放锁,如果尝试释放没有锁定的锁会raise RuntimerError 异常
加锁的目的
多个不同的线程能够访问同一个变量中的数据,为了不让访问的数据混乱,所以加锁,简单来说就是临界资源,必须一个访问完了,另一个才能来访问,所以加个锁
死锁问题:
循环依赖就是死锁的必要条件
尽可能保证每一个 线程只能同时保持一个锁,这样程序就不会被死锁问题所困扰
Lock 和RLock区别 (同一线程!!!)
简单来说 Lock 属于全局的, RLock属于线程,
简单认为Rlock里存在一个锁定池和一个计数器,只要acquire、release成对出现就行(+1 /-1) 0表示未锁定
同一个线程中,
Lock.acquire()
Lock.acquire()
Lock.release()
Lock.release()
这种情况会出现死锁,因为互斥的关系,加锁必须释放,才能再加锁
RLock.acquire()
RLock.acquire()
RLock.release()
RLock.release()
RLock不会出现这种情况,在同一线程中
测试代码在thread_lock_test.py
condition 类
一些问题互斥锁搞不定,该类提供一些对复杂问题的同步问题的支持
通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。
条件变量服从 上下文管理协议:使用 with 语句会在它包围的代码块内获取关联的锁
class threading.Condition(lock=None)
除了实现Lock() Rlock() 的方法外,还提供以下方法
在调用以下方法时没有获得锁,将会引发 RuntimeError 异常
1.wait(timeout=None) :释放锁,进去condition的等待池等待通知(其他线程调用notify/notify_all 唤醒它 ,)一旦被唤醒或者超时,它重新获得锁并返回。
2.notify():通知等待池,激活一个线程,不释放锁
3.notify_all():通知等待池,激活所有的线程,不释放锁
只能是一个线程执行过了wait(),在被阻塞过程中,另一个线程执行了notify()才可以
信号量对象
class threading.Semaphore(value=1)
一个信号量管理一个内部计数器,该计数器因 acquire() 方法的调用而-1,因 release() 方法的调用而+1。 计数器的值永远不会小于零;当 acquire() 方法发现计数器为零时,将会阻塞,直到其它线程调用 release() 方法。
class threading.BoundedSemaphore(value=1)
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常
定时器对象
class threading.Timer(interval, function, args=None, kwargs=None)
与线程一样,通过调用 start() 方法启动定时器。而 cancel() 方法可以停止计时器(在计时结束前), 定时器在执行其操作之前等待的时间间隔可能与用户指定的时间间隔不完全相同。
cancel()¶
停止定时器并取消执行计时器将要执行的操作。仅当计时器仍处于等待状态时有效。
事件对象
class threading.Event
is_set()
当且仅当内部标志为true时返回trueset()
set()
将内部标志设置为true
clear()
将内部标志设置为false
wait(timeout=None)
阻塞线程直到内部变量为true,
如果调用时内部标志为true,将立即返回
队列使用
创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。
将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。
将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。
Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize)
此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作
lock/rlock
condition 类测试
信号量类测试
定时器对象
事件对象
队列