有谁熟悉如何在python中实现多处理优先级队列?
答案 0 :(得分:5)
唉,它就像改变旧的Queue.Queue
的排队规则一样简单:后者实际上是根据模板方法模式设计的子类,并且只覆盖了钩子方法{{1} }和/或_put
可以轻松地允许更改排队规则(在2.6显式LIFO和优先级实现中提供,但即使在早期版本的Python中也很容易实现)。
对于多处理,在一般情况下(多个读者,多个编写者),我看不到如何实现优先级队列的解决方案,除了放弃队列的分布式性质;指定一个特殊的辅助进程,除了处理队列之外什么也不做,向它发送(基本上)RPC以创建具有指定规则的队列,执行put和get,获取有关它的信息,& c。因此,人们会遇到通常的问题,即确保每个进程都知道辅助进程的位置(主机和端口,等等)(如果进程总是在主进程启动时生成,则会更容易)。一个相当大的问题,特别是如果一个人希望以良好的性能做到这一点,可以防止aux proc的崩溃(需要将数据复制到从属进程,如果主机崩溃,则在奴隶之间分配“主选举”,等等)。从头开始这样做听起来像博士的工作。一个可能从Johnson's工作开始,或者依赖于ActiveMQ等一些非常通用的方法。
一些特殊情况(例如单个阅读器,单个作家)可能更容易,并且对于其有限的应用领域变得更快;但是,应该为该有限区域制定一个非常明确的限制规范 - 结果不会构成(通用)“多处理队列”,但只适用于给定的约束要求集。
答案 1 :(得分:2)
有一个错误会阻止真正的FIFO 阅读here。
构建优先级队列多处理设置的另一种方法肯定会很棒!
答案 2 :(得分:1)
虽然这不是一个答案,但它可以帮助您开发一个多处理队列。
这是我用Python的数组编写的一个简单的优先级队列类:
class PriorityQueue():
"""A basic priority queue that dequeues items with the smallest priority number."""
def __init__(self):
"""Initializes the queue with no items in it."""
self.array = []
self.count = 0
def enqueue(self, item, priority):
"""Adds an item to the queue."""
self.array.append([item, priority])
self.count += 1
def dequeue(self):
"""Removes the highest priority item (smallest priority number) from the queue."""
max = -1
dq = 0
if(self.count > 0):
self.count -= 1
for i in range(len(self.array)):
if self.array[i][1] != None and self.array[i][1] > max:
max = self.array[i][1]
if max == -1:
return self.array.pop(0)
else:
for i in range(len(self.array)):
if self.array[i][1] != None and self.array[i][1] <= max:
max = self.array[i][1]
dq = i
return self.array.pop(dq)
def requeue(self, item, newPrio):
"""Changes specified item's priority."""
for i in range(len(self.array)):
if self.array[i][0] == item:
self.array[i][1] = newPrio
break
def returnArray(self):
"""Returns array representation of the queue."""
return self.array
def __len__(self):
"""Returnes the length of the queue."""
return self.count
答案 3 :(得分:1)
我有相同的用例。但是有很多优先事项。
我最终要做的是每个优先级创建一个队列,我的进程工作者将尝试从这些队列中获取项目,从最重要的队列开始到不太重要的队列(从一个队列移动到另一个队列是当队列为空时完成)
答案 4 :(得分:0)
根据您的要求,您可以通过多种方式使用操作系统和文件系统。队列增长多大,速度有多快?如果队列可能很大但您愿意为每个队列访问打开几个文件,则可以使用BTree实现来存储队列和文件锁定以强制执行独占访问。缓慢而强劲。
如果队列仍然相对较小并且您需要它很快,那么您可以在某些操作系统上使用共享内存......
如果队列很小(1000个条目)并且您不需要 它真的很快你可以使用的东西 就像包含带文件锁定数据的文件的目录一样简单。如果小而慢可以,这将是我的偏好。
如果队列可能很大并且您希望它的平均速度很快,那么您可能应该使用像Alex建议的专用服务器进程。然而,这是颈部疼痛。
您的表现和尺寸要求是什么?
答案 5 :(得分:0)
受到@ user211505建议的启发,我把快速和肮脏的东西放在一起。
请注意,这不是多处理生产环境中优先级队列的难题的完整解决方案。但是,如果你只是搞乱或需要一些简短的项目,这可能符合要求:
from time import sleep
from datetime import datetime
from Queue import Empty
from multiprocessing import Queue as ProcessQueue
class SimplePriorityQueue(object):
'''
Simple priority queue that works with multiprocessing. Only a finite number
of priorities are allowed. Adding many priorities slow things down.
Also: no guarantee that this will pull the highest priority item
out of the queue if many items are being added and removed. Race conditions
exist where you may not get the highest priority queue item. However, if
you tend to keep your queues not empty, this will be relatively rare.
'''
def __init__(self, num_priorities=1, default_sleep=.2):
self.queues = []
self.default_sleep = default_sleep
for i in range(0, num_priorities):
self.queues.append(ProcessQueue())
def __repr__(self):
return "<Queue with %d priorities, sizes: %s>"%(len(self.queues),
", ".join(map(lambda (i, q): "%d:%d"%(i, q.qsize()),
enumerate(self.queues))))
qsize = lambda(self): sum(map(lambda q: q.qsize(), self.queues))
def get(self, block=True, timeout=None):
start = datetime.utcnow()
while True:
for q in self.queues:
try:
return q.get(block=False)
except Empty:
pass
if not block:
raise Empty
if timeout and (datetime.utcnow()-start).total_seconds > timeout:
raise Empty
if timeout:
time_left = (datetime.utcnow()-start).total_seconds - timeout
sleep(time_left/4)
else:
sleep(self.default_sleep)
get_nowait = lambda(self): self.get(block=False)
def put(self, priority, obj, block=False, timeout=None):
if priority < 0 or priority >= len(self.queues):
raise Exception("Priority %d out of range."%priority)
# Block and timeout don't mean much here because we never set maxsize
return self.queues[priority].put(obj, block=block, timeout=timeout)