Queue队列
2.原子操作:这件事情是不可再分的,如变量的赋值,不可能一个线程在赋值,到一半切到另外一个线程工作去了……但是一些数据结构的操作,如栈的push什么的,并非是原子操作,比如要经过栈顶指针上移、赋值、计数器加1等等,在其中的任何一步中断,切换到另一线程再操作这个栈时,就会产生严重的问题,因此要使用锁来避免这样的情况。比如加锁后的push操作就可以认为是原子的了……
3.阻塞:所谓的阻塞,就是这个线程等待,一直到可以运行为止。最简单的例子就是一线程原子操作下,其它线程都是阻塞状态,这是微观的情况。对于宏观的情况,比如服务器等待用户连接,如果始终没有连接,那么这个线程就在阻塞状态。同理,最简单的input语句,在等待输入时也是阻塞状态。
4.在创建线程后,执行p.start(),这个函数是非阻塞的,即主线程会继续执行以后的指令,相当于主线程和子线程都并行地执行。所以非阻塞的函数立刻返回值的~
对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列。
LifoQueue后入先出(LIFO)队列
PriorityQueue 优先队列
此模块一般用于和多线程配合
1.Queue.qsize() 返回队列的大小
2.Queue.empty() 如果队列为空,返回True,反之False
3.Queue.full() 如果队列满了,返回True,反之False
4.Queue.get([block[, timeout]]) 获取队列,timeout等待时间
5.Queue.get_nowait() 相当Queue.get(False)
6.非阻塞 Queue.put([block[, timeout]]) 写入队列,timeout等待时间
7.Queue.put_nowait(item) 相当Queue.put(item, False)
8.Queue.task_done() 每次从queue中get一个数据之后,当处理好相关问题,最后调用该方法,主要与q.join配合使用,以提示q.join是否停止阻塞
9Queue.join(): 实际上意味着等到队列为空,再执行别的操作,阻塞,直到queue中的数据均被删除或者处理。为队列中的每一项都调用一次
快速消费者的例子
import Queue,threading,time,random
class consumer(threading.Thread):
def __init__(self,que):
threading.Thread.__init__(self)
self.daemon = False
self.queue = que
def run(self):
while True:
if self.queue.empty():
break
item = self.queue.get()
#processing the item
time.sleep(item)
print self.name,item
self.queue.task_done()
return
que = Queue.Queue()
for x in range(10):
que.put(random.random() * 10, True, None)
consumers = [consumer(que) for x in range(3)]
for c in consumers:
c.start()
que.join()
可以看到,生产者首先将队列准备好,然后消费者再使用。
最后只要使用que.join即可在queue为空的时候,停止三个进程;此时主线程即可退出。
快速消费者例子
import Queue,threading,time,random
class consumer(threading.Thread):
def __init__(self,que):
threading.Thread.__init__(self)
self.daemon = False
self.queue = que
def run(self):
while True:
item = self.queue.get()
if item == None:
break
#processing the item
print self.name,item
self.queue.task_done()
self.queue.task_done()
return
que = Queue.Queue()
consumers = [consumer(que) for x in range(3)]
for c in consumers:
c.start()
for x in range(10):
item = random.random() * 10
time.sleep(item)
que.put(item, True, None)
que.put(None)
que.put(None)
que.put(None)
que.join()
这是一个快速消费者的例子,首先,由于队列中开始没有任何数据,所以无法使用上面的empty确认退出run;如果使用了empty语句,则虽然三个子线程都已经退出,但是主线程会卡到que.join这里,因为队列中存在了10个元素。
所以这里引入了None;使用None作为结束判断。
当然也可以把子线程设置为deamon,一但生产完成,开始que.join()阻塞直至队列空就结束主线程,子线程虽然在阻塞等待队列也会因为deamon属性而被强制关闭。。。。
生产者消费者通用例子
#encoding=gbk
import threading
import time
condition = threading.Condition()
products = 0
class Producer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products < 10:
products += 1;
print "Producer(%s):deliver one, now products:%s" %(self.name, products)
condition.notify()
else:
print "Producer(%s):already 10, now products:%s" %(self.name, products)
condition.wait()
condition.release()
time.sleep(2)
class Consumer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products > 1:
products -= 1
print "Consumer(%s):consume one, products:%s" %(self.name, products)
condition.notify()
else:
print "Consumer(%s):only 1, stop consume" %(self.name)
condition.wait()
condition.release()
time.sleep(2)
if __name__ == "__main__":
for p in range(0, 2):
p = Producer()
p.start()
for c in range(0, 10):
c = Consumer()
c.start()
最后,queue是线程安全的,但不是进程安全的,多进程情况下可以使用multiprocessing.Queue()