python实现阻塞队列_python实现阻塞队列

目录

一、初始化函数:

二、 task_done(self):

三、join(self):

四、put(self, item, block=True, timeout=None):

五、阻塞的情况

怎么实现阻塞队列?当然是靠锁,但是应该怎么锁?一把锁能在not_empty,not_full,all_tasks_done三个条件之间共享。好比说,现在有线程A线程B,他们准备向队列put任务,队列的最大长度是5,线程A在put时,还没完事,线程B就开始put,队列就塞不下了,所以当线程A抢占到put权时应该加把锁,不让线程B对队列操作。鬼畜区经常看到的计数君,在线程中也同样重要,每次put完unfinished要加一,get完unfinished要减一。

import threading

import time

from collections import deque

class BlockQueue:

def __init__(self, maxsize=0):

self.mutex = threading.Lock()

self.maxsize = maxsize

self.not_full = threading.Condition(self.mutex)

self.not_empty = threading.Condition(self.mutex)

self.all_task_done = threading.Condition(self.mutex)

self.unfinished = 0

一、初始化函数:

一把锁三个条件(self.mutex,(self.not_full, self.not_empty, self.all_task_done)),最大长度与计数君(self.maxsize,self.unfinished)

def task_done(self):

with self.all_task_done:

unfinish = self.unfinished - 1

if unfinish <= 0:

if unfinish < 0:

raise ValueError("The number of calls to task_done() is greater than the number of queue elements")

self.all_task_done.notify_all()

self.unfinished = unfinish

二、 task_done(self):

每一次put完都会调用一次task_done,而且调用的次数不能比队列的元素多。计数君对应的方法,unfinished<0时的意思是调用task_done的次数比列表的元素多,这种情况就会抛出异常。

def join(self):

with self.all_task_done:

while self.unfinished:

self.all_task_done.wait()

三、join(self):

阻塞方法,是一个十分重要的方法,但它的实现也不难,只要没有完成任务就一直wait(),就是当计数君unfinished > 0 时就一直wait()知道unfinished=0跳出循环。

def put(self, item, block=True, timeout=None):

with self.not_full:

if self.maxsize > 0:

if not block:

if self._size() >= self.maxsize:

raise Exception("The BlockQueue is full")

elif timeout is not None:

self.not_full.wait()

elif timeout < 0:

raise Exception("The timeout period cannot be negative")

else:

endtime = time.time() + timeout

while self._size() >= self.maxsize:

remaining = endtime - time.time()

if remaining <= 0.0:

raise Exception("The BlockQueue is full")

self.not_full.wait(remaining)

self.queue.append(item)

self.unfinished += 1

self.not_empty.notify()

四、put(self, item, block=True, timeout=None):

block=True一直阻塞直到有一个空闲的插槽可用,n秒内阻塞,如果在那个时间没有空闲的插槽,则会引发完全的异常。Block=False如果一个空闲的槽立即可用,则在队列上放置一个条目,否则就会引发完全的异常(在这种情况下,“超时”将被忽略)。有空位,添加到队列没结束的任务+1,他最后要唤醒not_empty.notify(),因为一开始是要在没满的情况下加锁,满了就等待not_full.wait,当put完以后就有东西了,每当一个item被添加到队列时,通知not_empty等待获取的线程会被通知。

def get(self, block=True, timeout=None):

with self.not_empty:

if not block:

if self._size() <= 0:

raise Exception("The queue is empty and you can't call get ()")

elif timeout is None:

while not self._size():

self.not_empty.wait()

elif timeout < 0:

raise ValueError("The timeout cannot be an integer")

else:

endtime = time.time() + timeout

remaining = endtime - time.time()

if remaining <= 0.0:

raise Exception("The BlockQueue is empty")

self.not_empty.wait(remaining)

item = self._get()

self.not_full.notify()

return item

五、阻塞的情况

如果可选的args“block”为True,并且timeout是None,则在必要时阻塞,直到有一个项目可用为止。如果“超时”是一个非负数,它会阻塞n秒,如果在那个时间内没有可get()的项,则会抛出空异常。否则'block'是False,如果立即可用,否则就会抛出空异常,在这种情况下会忽略超时。同理要唤醒not_full.notify

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值