Thread-safe priority queue using Queue.Queue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import Queue
class PriorityQueue(Queue.Queue):
def _put(self, item):
data, priority = item
self._insort_right((priority, data))
def _get(self):
return self.queue.pop(0)[1]
def _insort_right(self, x):
"""Insert item x in list, and keep it sorted assuming a is sorted.
If x is already in list, insert it to the right of the rightmost x.
"""
a = self.queue
lo = 0
hi = len(a)
while lo < hi:
mid = (lo+hi)/2
if x[0] < a[mid][0]: hi = mid
else: lo = mid+1
a.insert(lo, x)
def test():
pq = PriorityQueue()
pq.put(('b', 1))
pq.put(('a', 1))
pq.put(('c', 1))
pq.put(('z', 0))
pq.put(('d', 2))
while not pq.empty():
print pq.get(),
test() # prints z b a c d
|
Tags: algorithms
pop or get? Queue.Queue does not have a pop() method. It does however have a get() method.
output. For me, this outputs: z b a c d
output. typo corrected.
pop method. I don't quite understand what you mean. the pop() call in _get-calls the internal queue-data structure, which is python list.
using bisect.insort_right(). Would using bisect.insort_right() cause problems? i.e.
seems to work nicely.
I also found a 'top' method useful:
bisect.insort_right will not work. Using bisect.insort_right as you suggest would not work.
Assuming item is a tuple of (priority, data), then it would be inserted amongst other items in the queue with the same priority, but sorted by the value of its data, rather than by its arrival time.
You may be able to hack around this with something like:
if the data are all integers.
bisection. why bother with bisection if you're just going to use an O(n) insert?
Why not use a heapqueue. Like this:
prints b, c, e, a, d
Using bisect module. I don't really understand the maths of heapq, but it doesn't seem to maintain the existing ordering. In fact if you use the example from the published 2nd edition cookbook, if you insert a series of items with the same time.time() value they get ordered according to their (undecorated) item value which is not so good.
And I'm a bit bothered by not re-using the bisect algorithm, so here is a version that doesn't sort on item value, but does use the bisect module.
Priority Queue Semantics. Maintaining the existing ordering isn't usually what a priority queue does. If you have several objects with the same priority, it doesn't matter what order you address them in. (After all, they have the /same/ priority.) ER-style priority, like your example, is a different strategy (items that have the same value for their priority don't technically have the same 'priority'). Often, applications that require priority queues (like implementations of Dijkstra's algorithm, or A* search) would much rather have the performance boost of a heap versus the maintenance of first-come ordering. (heap is O(logN) to insert, list insort is O(NlogN))
It's a trade-off of performance versus a specific semantic. I am curious: what situation did you create this PriorityQueue for that demanded first-come ordering?