有Q一、Q二、……、Qn n个队列,每一个队列有一个权值W一、W二、……、Wn,须要每次从其中一个队列取出一个元素,使得从不一样队列取出的元素数量比例服从权值的比例。html
这正是网络流量调度场景中的“带权轮询调度”(Weighted Round-Robin Scheduling,WRR),有现成的算法可用。python
为了简单起见,先考虑最简单的状况,令 W1 = W2 = ... = Wn,那么“带权轮询调度”退化成“轮询调度”(Round-Robin Scheduling,RR),RR实现很简单,而后考虑权值不一样的状况。算法
# count N = 3 # Round-Robin Scheduling def rr_select(): last = N - 1 while True: current = (last + 1) % N last = current yield current rr_test = rr_select() for i in range(1000): print(rr_test.__next__())
N是队列的个数,0到N-1数字表明这N个队列。微信
RR会依次从每一个队列取出元素,很简单无需过多叙述。网络
# count N = 3 weight = (60, 30, 10) # 最大公约数 def gcd(nums): m = nums[0] for n in nums[1:]: while n != 0: m, n = n, m % n return m # Weighted Round-Robin Scheduling def wrr_select(): current = N - 1 current_weight = 0 while True: current = (current + 1) % N if current == 0: current_weight -= gcd(weight) if current_weight <= 0: current_weight = max(weight) if weight[current] >= current_weight: yield current wrr_test = wrr_select() for i in range(1000): print(wrr_test.__next__())
这个算法须要解释一下。code
先看一下取前10个元素的结果:htm
current_weight 从哪些队列取出了元素 60 0 50 0 40 0 30 0 1 20 0 1 10 0 1 2
也就是每次for i in (0, 1, 2)
的小周期内,当current_weight > weight[i]
时,就把i
选出来。当current_weight
等于0
了,就再从头开始,这算一个大周期。一个大周期包含max(weight)/gcd(weight)
个小周期。blog
那如何证实这样取是符合权值比例的?队列
能够看到每一个小周期中,都是要从权值最大的队列里拿走一个元素的,能够看做拿权值最大的那个做为基准,而后权值较小的直接拿它对比。那仅看权值为10的即可,10是60的1/6,把60分6分,只有1份是应该给10的,因此60知道降到10才知足10的条件。权值30的同理。ip
其实max(weight)和gcd(weight)均可以选择别的,但选它们两个能够知足最细粒度的平均,即每取出任意10个连续的中间结果,就必然服从权值比例,能够认为是最优的。
WRR的运行结果是固定的,若是须要考虑随机性的话,须要再作一些额外工做。简单的话能够先对队列的顺序作随机,但这样实际的顺序仍是固定的。能够按实际须要频繁暂存必定(随机)数量的结果,再随机处理后依次输出。
付费解决 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等领域相关问题,灵活订价,欢迎咨询,微信 ly50247。