信号量
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。
计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。


1 import threading,time 2 class myThread(threading.Thread): 3 def run(self): 4 if semaphore.acquire(): 5 print(self.name) 6 time.sleep(5) 7 semaphore.release() 8 if __name__=="__main__": 9 semaphore=threading.Semaphore(5) //计数器为5 10 thrs=[] 11 for i in range(100): 12 thrs.append(myThread()) 13 for t in thrs: 14 t.start() 15 //执行结果:每五秒打印出5条线程名字
条件变量同步
有一类线程需要满足条件之后才能够继续执行,Python提供了threading.Condition 对象用于条件变量线程的支持,它除了能提供RLock()或Lock()的方法外,还提供了 wait()、 notify()、notifyAll()方法。
lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,默认RLock,建议默认,RLock具备Lock功能
wait():条件不满足时调用,线程会释放锁并进入等待阻塞;
notify():条件创造后调用,通知等待池激活一个线程;
notifyAll():条件创造后调用,通知等待池激活所有线程。


1 import threading,time 2 from random import randint 3 class Producer(threading.Thread): 4 def run(self): 5 global L 6 val=randint(0,100) 7 print('生产者',self.name,":Append"+str(val),L) 8 if lock_con.acquire(): 9 L.append(val) 10 lock_con.notify() //通知等待池激活一个线程 11 lock_con.release() 12 class Consumer(threading.Thread): 13 def run(self): 14 global L 15 lock_con.acquire() //被激活的线程不会从阻塞代码行运行,而是从新获取锁运行 16 if len(L)==0: 17 lock_con.wait() //释放锁进入阻塞状态,进入等待池的等待激活 18 print('消费者',self.name,":Delete"+str(L[0]),L) 19 del L[0] 20 lock_con.release() 21 22 if __name__=="__main__": 23 24 L=[] 25 lock_con=threading.Condition() 26 threads=[] 27 for i in range(5): 28 threads.append(Producer()) 29 threads.append(Consumer()) 30 for t in threads: 31 t.start() 32 for t in threads: 33 t.join()
同步条件
同步条件和条件变量同步都具有通信功能,只是少了锁功能,当条件同步设计于不访问共享资源的条件环境时可以使用同步条件。event=threading.Event():条件环境对象,event内部具有一个布尔类的状态值,初始值 为False。
event.isSet():返回event当前状态值;
event.wait():此时event状态值为False,线程被阻塞;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。


1 import threading,time 2 class Boss(threading.Thread): 3 def run(self): 4 print("BOSS:今晚大家都要加班到22:00。") // 2:打印 5 event.isSet() or event.set() // 3:判断event当前状态值并将event状态值设置为True,激活阻塞池中的线程 6 time.sleep(5) // 4:等待5秒 7 print("BOSS:<22:00>可以下班了。") // 9:打印 8 event.isSet() or event.set() // 10:判断event当前状态值并将event状态值设置为True,激活阻塞池中的线程 9 class Worker(threading.Thread): 10 def run(self): 11 event.wait() // 1:event 状态值为False,线程阻塞 12 print("Worker:哎……命苦啊!") // 5:打印 13 time.sleep(0.25) // 6:等待0.25秒 14 event.clear() // 7:恢复event状态值设为False 15 event.wait() // 8:线程阻塞 16 print("Worker:OhYeah!") // 11:打印 17 if __name__=="__main__": 18 event=threading.Event() 19 threads=[] 20 for i in range(5): 21 threads.append(Worker()) 22 threads.append(Boss()) 23 for t in threads: 24 t.start() 25 for t in threads: 26 t.join() 27 28 //执行结果 29 BOSS:今晚大家都要加班到22:00。 30 Worker:哎……命苦啊! 31 Worker:哎……命苦啊! 32 Worker:哎……命苦啊! 33 Worker:哎……命苦啊! 34 Worker:哎……命苦啊! 35 BOSS:<22:00>可以下班了。 36 Worker:OhYeah! 37 Worker:OhYeah! 38 Worker:OhYeah! 39 Worker:OhYeah! 40 Worker:OhYeah!
多线程利器-队列(queue)(重点)
创建一个“队列”对象
import Queue
q = Queue.Queue([maxsize])
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize为0就表示队列长度无限,默认为0。
将一个值放入队列中
q.put(item, [block])
调用队列对象的put()方法在队列末尾追加一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。当一个队列长度为10,并且已经put进10个元素,如果再put第11个元素,此时则取决put第11个元素时block的值,如果block为1,则程序在这一行进入阻塞状态;如果block为0,则程序终止执行,并抛出Full异常。
将一个值从队列中取出
q.get()
调用队列对象的get()方法从队列起始位置删除并返回一个项目。可选参数为block,与put()方法的block参数相同,block参数默认为1。当队列为空时,如果block为1,则程序在这一行进入阻塞状态;如果block为0,则程序终止执行,并抛出empty异常。
Python Queue模块有三种队列及构造函数(后两种不常使用):
1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize)
queque模块中的常用方法(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() 实际上意味着等到队列为空,再执行别的操作
队列的优点就是多个线程操作队列时,不会出现数据混乱的可能,这是因为在队列内部对这段数据加了锁,所以当多个线程需要操作同一份数据时,我们可以使用队列。


1 import threading, queue, random 2 3 class Producer(threading.Thread): 4 5 def run(self): 6 val = random.randint(0, 100) 7 q.put(val) 8 print('生产者生产了%s台电脑'%val) 9 10 class Consumer(threading.Thread): 11 12 def run(self): 13 while True: 14 try: 15 print('批发商买走%s台电脑'%q.get(0)) 16 except Exception: 17 break 18 19 q = queue.Queue() 20 21 threading = [Producer(), Producer(), Producer(), Consumer()] 22 for t in threading: 23 t.start() 24 25 //执行结果 26 生产者生产了98台电脑 27 生产者生产了40台电脑 28 生产者生产了44台电脑 29 批发商买走98台电脑 30 批发商买走40台电脑 31 批发商买走44台电脑