有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。