我有一个继承自Queue
的类,并由另一个工厂类使用:
class myQueue(Queue):
def putall(self , mobjects , *args):
self.put(mobject, *args )
def getall(self , number , *args ):
return [self.get(*args) for _ in xrange(number)]
我在外部使用putall
和getall
,并希望它们是原子的。我怎样才能做到这一点?我使用的是Python 2.6。
答案 0 :(得分:1)
为了使putall
和getall
成为原子,您需要持有一个锁,以防止任何其他修改Queue
的方法运行。显而易见的选择是使用mutex
内部使用的Queue
对象,但这是使用threading.Lock
实现的,这意味着它不能递归地使用。这意味着天真的解决方案将导致死锁:
from Queue import Queue
import threading
class myQueue(Queue):
def putall(self , objects , *args):
with self.mutex:
for object in objects:
self.put(object, *args) # This will hang.
def getall(self , number , *args ):
with self.mutex:
return [self.get(*args) for _ in xrange(number)] # This will hang
q = myQueue()
q.putall(["1", "2", "3"])
print(q.getall(2))
这会在putall
和getall
内陷入僵局,因为两者都会尝试递归获取mutex
(putall
/ getall
中的第一个,然后再次{ {1}} / put
)。你有几个选择来解决这个问题。最简单的方法是使用get
覆盖mutex
内创建的Queue.__init__
实例。这还需要重新创建使用threading.RLock
:
threading.Condition
个对象
mutex
输出:
from Queue import Queue
import threading
class myQueue(Queue):
def __init__(self, *args, **kwargs):
Queue.__init__(self, *args, **kwargs)
self.mutex = threading.RLock()
self.not_empty = threading.Condition(self.mutex)
self.not_full = threading.Condition(self.mutex)
self.all_tasks_done = threading.Condition(self.mutex)
def putall(self , objects , *args):
with self.mutex:
for object in objects:
self.put(object, *args)
def getall(self , number , *args ):
with self.mutex:
return [self.get(*args) for _ in xrange(number)]
q = myQueue()
q.putall(["1", "2", "3"])
print(q.getall(2))
请注意,您在这里依赖于['1', '2']
的实现细节,如果在新版本的Python中实现更改,这会使这种情况更容易破解。更加面向未来的Queue
版本将包装myQueue
实例,为其所有需要互斥锁的公共方法提供实现,并使用您自己的递归锁来同步这些方法。