我有一个服务器应用程序,它接受传入的查询并执行它们。如果有太多查询,则应将它们排队,如果执行了其他一些查询,则也应执行排队的查询。因为我想传递具有不同优先级的查询,所以我认为使用priority_queue将是最好的选择。
例如,接受查询的数量 (a) 达到限制,新的查询将存储在队列中。所有查询的优先级均为 1(最低),如果 (a) 中的某些查询得到执行,程序将从队列中选择具有最高优先级的查询并执行它。还是没问题。现在有人正在发送优先级为 5 的查询,该查询被添加到队列中。由于这是具有最高优先级的查询,因此一旦运行的查询不再达到限制,应用程序就会执行该查询。最坏的情况可能是,500 个优先级为 1 的查询已排队,但不会被执行,因为有人总是发送优先级为 5 的查询,因此这 500 个查询将排队很长时间。为了防止这种情况,我想增加所有优先级低于优先级的查询的优先级,在本例中,优先级低于 5。因此,如果优先级为 5 的查询被拉出队列中所有其他优先级<<的查询5 应增加 0.2。这样,即使可能有 100 个具有较高优先级的查询,低优先级的查询也不会永远排队。
我真的希望有人可以帮助我解决优先级问题:
由于我的查询由一个对象组成,我认为这样的事情可能会起作用:
class Query {
public:
Query( std::string p_stQuery ) : stQuery( p_stQuery ) {};
std::string getQuery() const {return stQuery;};
void increasePriority( const float fIncrease ) {fPriority += fIncrease;};
friend bool operator < ( const Query& PriorityFirst, const Query& PriorityNext ) {
if( PriorityFirst.fPriority < PriorityNext.fPriority ) {
if( PriorityFirst.fStartPriority < PriorityNext.fStartPriority ) {
Query qTemp = PriorityFirst;
qTemp.increasePriority( INCREASE_RATE );
}
return true;
} else {
return false;
}
};
private:
static const float INCREASE_RATE = 0.2;
float fPriority; // current priority
float fStartPriority; // initialised priority
std::string stQuery;
};
I have a server application which accepts incomming queries and executes them. If there are too many queries they should be queued and if some of the other queries got executed the queued queries should be executed as well. Since I want to pass queries with different priorities I think using a priority_queue would be the best choice.
e.g. The amout of the axcepting queries (a) hit the limt and new queries will be stored in the queue. All queries have a priority of 1 (lowest) if some of the queries from (a) get executed the programm will pick the query with the highest priority out of the queue and execute it. Still no problem. Now someone is sending a query with a priority of 5 which gets added to the queue. Since this is the query with the highest priority the application will execute this query as soon as the running queries no longer hit the limit. There might be the worst case that 500 queries with a priority of 1 are queued but wont be executed since someone is always sending queries with a priority of 5 hence these 500 queries will be queued for a looooong time. In order to prevent that I want to increase the prioritiy of all queries which have a lower priority than the query with the higher priority, in this example which have a priority lower than 5. So if the query with a priority of 5 gets pulled out of the queue all other queries with a priority < 5 should be increased by 0.2. This way queries with a low priority wont be queued for ever even if there might be 100 queries with a higher priority.
I really hope someone can help me to solve the problem with the priorities:
Since my queries consist of an object I thought something like this might work:
class Query {
public:
Query( std::string p_stQuery ) : stQuery( p_stQuery ) {};
std::string getQuery() const {return stQuery;};
void increasePriority( const float fIncrease ) {fPriority += fIncrease;};
friend bool operator < ( const Query& PriorityFirst, const Query& PriorityNext ) {
if( PriorityFirst.fPriority < PriorityNext.fPriority ) {
if( PriorityFirst.fStartPriority < PriorityNext.fStartPriority ) {
Query qTemp = PriorityFirst;
qTemp.increasePriority( INCREASE_RATE );
}
return true;
} else {
return false;
}
};
private:
static const float INCREASE_RATE = 0.2;
float fPriority; // current priority
float fStartPriority; // initialised priority
std::string stQuery;
};
发布评论
评论(6)
您想要实现多少个离散优先级值?如果它们的数量很小(例如 256 个级别),那么使用 256 个简单队列代替单个优先级队列更有意义(这就是优先级进程调度程序在某些操作系统中的实现方式)。最初,以优先级 1 发送的事件被放置在队列 #1 中。然后有人发送 prio=25 事件,并将其放置在队列 #25 中。读取器从最高的非空队列(在本例中为#25)读取事件,并将 25 以下的所有非空队列上的事件向上移动一个槽(整个队列#1 移动到队列#2,依此类推) 。我非常确定这一切都可以在 O(k) 内完成(其中 k 是优先级的数量),无论是使用 std::move 还是使用 std::swap 或使用 list::splice。
通过移动或交换,将队列 #1 移动到队列 #2 之前的位置应该是 O(1),并且如果 prio=25 队列的剩余部分不为空,则将所有元素从队列 #24 向上移动到队列 #25如果队列是 std::list 的并且使用
list::splice()
,则为 O(1)。How many discrete priority values do you want to implement? If their number is small (say, 256 levels), then instead of a single priority queue it makes more sense to have 256 simple queues (this is how priority process schedulers are implemented in some OSes). Initially your events sent with priority 1 are placed on queue #1. Then someone sends a prio=25 event, and it is placed on queue #25. The reader reads the event from the highest non-empty queue (in this case #25) and the events on all non-empty queues under 25 are moved up a slot (the entire queue #1 is moved to queue #2, etc). I am pretty sure this could all be done in O(k) (where k is the number of priority levels), either with std::move or with std::swap or with list::splice.
Moving queue #1 to the position earlier taken by queue #2 should be O(1) with move or swap, and if the remainder of prio=25 queue is not empty, then moving all elements up from queue #24 into queue #25 is O(1) if the queues are std::list's and
list::splice()
is used.如果排序条件发生变化,
std::priority_queue
无法重新组织自身。您需要自己管理。我建议只使用 std::vector 和两种方法之一来维护它。
有两种情况:如果您重新确定优先级的频率比删除元素的频率高(听起来并非如此),则只需保持其未排序并使用 min_element 来查找需要时要删除的项目。
否则,更好的方法可能是使用 Kristo 的方法并维护自己的堆。当您重新调整调用
make_heap
的优先级时,要添加使用push_heap
,并使用pop_heap
获取顶部项目。A
std::priority_queue
doesn't have any way to reorganize itself if your sort criteria changes. You'll nede to manage it yourself.I would suggest just using a
std::vector
and one of two approaches to maintain it.There are two cases: If you're reprioritizing rather more often than you remove elements (which sounds like is not the case), just keep it unsorted and use min_element to find the item to remove when nedeed.
Otherwise probably better is to use Kristo's approach and maintain your own heap. When you reprioritize call
make_heap
, to add usepush_heap
, and to get the top item usepop_heap
.如果您需要修改优先级,则不能使用priority_queue,因为没有接口可以访问所有元素。您最好使用
std::vector
和std::make_heap
。If you need to modify the priorities, then you can't use a priority_queue because there's no interface to access all the elements. You're better off with
std::vector
andstd::make_heap
.ACE 框架可能会提供一些可以帮助您的东西。请参阅类 ACE_Dynamic_Message_Queue 和 ACE_Laxity_Message_Strategy。
我还没有使用过这个特定的类,所以我无法给你一个例子。
但思路是这样的:
The ACE framework probably provides something that could help you. See classes ACE_Dynamic_Message_Queue and ACE_Laxity_Message_Strategy.
I haven't worked with this particular classes yet, so I could not give you an example.
But the idea is as follows:
首先对您的代码进行一些评论:
我写了一个示例,将priority_queue覆盖为您想要的特定队列,我希望您可以从这里继续。该行为应该在队列中实现,而不是在 Query 类中实现,这只应该提供必要的访问器来允许该行为。查询类不应该了解队列。
基本上它复制了普通队列的大小和空,并创建了 2 个新方法来插入和获取查询(push、pop 和 top 被禁用)。 Insert 仅调用push,get 调用top、pop 并使用本地容器上的for_each 调用更新所有优先级。最后提供了一个显示功能的小程序。
此外,它基于弹出和推送中的堆管理。据我所知,由于每个元素的线性变化,这将正确工作,推送之间的顺序不会改变;)。
First of all some comments on your code:
I wrote an example that overrides the priority_queue to the specific queue you want, I hope you can continue from here. The behaviour should be implemented in the queue, not in the Query class at all, this only should provide the necessary accessors to allow this behaviour. The Query class should have no knowledge about the Queue.
Basically it copies the size and empty of the normal queue, and creates 2 new methods to insert and get queries (push, pop and top are disabled). Insert just calls push, get calls both top, pop and updates all priorities using a for_each call on the local container. Finally a small program is provided showing functionality.
Also, it is based on the heap managing in pop and push. This will work correctly as far as I know because of the linear change on every element, the order does not change between pushes ;).
我会使用 std::deque 并自己构建其余部分(如果您只是使用 C++,没有可能有帮助的外部库)。 make_heap(std::priority_queue 使用的)的其他建议的问题是它不稳定。在这种情况下缺乏稳定性意味着优先级内的排序得不到保证,并且可能出现饥饿。
I would go with a std::deque and build the rest yourself(if you are just using C++ with no external libs that might help). The problem with the other suggestions of make_heap (which is what std::priority_queue uses) is that it isn't stable. Lack of stability in this case means that ordering isn't guarantied within a priority and starvation is possible.