thread 4, queue

来源:互联网 发布:网络维护难点分析 编辑:程序博客网 时间:2024/06/05 11:41

Queue队列

前期唠叨:
1.多线程采用的是分时复用技术,即不存在真正的多线程,cpu做的事是快速地切换线程,以达到类似同步运行的目的,因为高密集运算方面多线程是没有用的,但是对于存在延迟的情况(延迟IO,网络等)多线程可以大大减少等待时间,避免不必要的浪费。

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,randomclass 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()        returnque = 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()



0 0
原创粉丝点击