虽然我喜欢排队,但编码时遇到的问题是如果我使用队列则无法完成。基本上我有一个生产者 - 工人体系结构,许多生产者正在生产工作,许多工人正在消费和处理它们。队列是一个自然的选择。
但是,由于生成了大量的作业,我提出了解决方案,在他们仍在等待处理时批量处理作业,并且可能从队列中清除其中一些作业,以便队列将没有很多东西。例如。对于某些作业,时间戳已过期,不再需要处理它们。而不是工人来解决这个问题(这在我的情况下是昂贵的,而且我无论如何都无法触及工人),我想从队列中清除这些类型的结果,而这些工作仍在等待处理。
因为我不能只从中间队列中获取项目,所以我决定将体系结构从队列更改为字典(不能使用列表,因为我出于某种原因需要键/值对)并且以这种方式实现dict它的行为与队列完全一样。所以这是我的待办事项列表:
所以我去实现了下面的代码。请注意lock.acquire()
的使用def put(self, userId, job):
self.__lock.acquire()
try:
if userId in self.__queue:
#merge the 'job' and the dict already present in 'self.__queue[userId]'
else:
self.__queue[userId] = job
finally:
self.__lock.release()
def pop(self, wait = True):
self.__lock.acquire()
try:
if wait:
while(len(self.__queue) == 0):
pass
#pop the 'first' value in dict.
#Please do not worry that dict has no first or last value.
#I sort the dict keys, and pop the first value.
finally:
self.__lock.release()
现在注意pop()方法。假设dict中没有数据,因此其中一个worker将持有锁,其他worker将等待锁释放。但是,push()方法也使用相同的锁,因此它是一个死锁情况。没有数据甚至会进入dict,因为pop()持有锁。 但是如果我从push方法()中移除锁定,以便数据可以随时出现,我担心在工人的竞争条件下覆盖一些数据。请参阅下面的示例。
在else条件下,如果该用户不在dict中,则创建新记录 - 我不希望一个worker创建新密钥,同时另一个worker也创建相同的密钥,这个新密钥会覆盖旧密钥,因此我会丢失数据。我理解它是一个非常小的错误窗口,如果你认为它实际上等于零,我准备完全从push()方法中删除锁。
我有一个很大的机会,我过于愚蠢而且错过了一些观点,但我现在想不出任何事情。感谢您抽出宝贵时间来解决这个问题。 :)
所以根据@Kevin的说法,这是我的版本"条件"。
def put(self, userId, job):
self.__condition.acquire()
try:
if userId in self.__queue:
#merge the 'job' and the dict already present in 'self.__queue[userId]'
else:
self.__queue[userId] = job
finally:
self.__condition.notify()
self.__condition.release()
def pop(self, wait = True):
self.__condition.acquire()
try:
if wait:
while True:
if(len(self.__queue) > 0):
break
self.__condition.wait()
#pop the 'first' value in dict.
#Please do not worry that dict has no first or last value.
#I sort the dict keys, and pop the first value.
finally:
self.__condition.release()
这是我第一次有条件,因此我将我的代码放在这里,以便其他人可以验证。谢谢。
答案 0 :(得分:0)
在这里使用锁可能不是最好的选择。而是在.wait()
方法(您当前拥有pop()
)中为其创建condition和pass
。然后,在.notify()
中调用put()
(最后,在您发布之前,但不在最后,或者您不小心将锁定锁定)。