thread 4, queue

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,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()



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值