日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java 实现调度算法 包括 FCFS(FIFO)、优先权排队、循环排队、加权公平排队(WFQ)

發(fā)布時間:2023/12/14 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 实现调度算法 包括 FCFS(FIFO)、优先权排队、循环排队、加权公平排队(WFQ) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 為什么要用調(diào)度算法?
  • 調(diào)度算法
    • 先來先服務(wù)(FCFS First-Come First-Server)
    • 優(yōu)先權(quán)排隊(Priority Queuing)
    • 循環(huán)排隊(Round Queuing)
    • 加權(quán)公平排隊(Weighted Fair Queuing)
      • 加權(quán)輪詢
      • 加權(quán)隨機(jī)

為什么要用調(diào)度算法?

首先要聲明這里實現(xiàn)的是應(yīng)用層調(diào)度算法,針對的是請求,而不是操作系統(tǒng)的進(jìn)程調(diào)度算法,在平常處理請求時,如果請求并發(fā)量不大,是一個接一個過來的,那我們沒有選擇只有一個接一個處理請求了,但是如果請求并發(fā)量很多,那我們就有選擇先執(zhí)行哪個請求的權(quán)力了,而選擇先執(zhí)行哪個請求就是調(diào)度算法,可以知道這里的請求都是我們要執(zhí)行的請求,只是執(zhí)行的順序先后不同而已,在這之前呢,會不會有要執(zhí)行的請求和被拒絕執(zhí)行的請求呢,也是有的,那個步驟叫做限流,可以看我這篇文章 漏桶(令牌桶)限流算法

調(diào)度算法

先來先服務(wù)(FCFS First-Come First-Server)

該算法也叫先進(jìn)先出 FIFO(First Input First Outer),這是非常公平的算法,實現(xiàn)也非常簡單,使用一個隊列,隊列中的節(jié)點可以有兩種構(gòu)成

  • 隊列中每個結(jié)點可以是存儲著HTTP請求信息(如URL和請求參數(shù))的對象,如果是這種節(jié)點,我們可以在出隊列時調(diào)用執(zhí)行處理請求任務(wù)的線程獲取這個節(jié)點存儲的信息,然后執(zhí)行就可以了
  • 隊列中每個結(jié)點也可以是一個阻塞的線程,如果是這種節(jié)點,我們可以在出隊列的時候直接喚醒該線程,它會自動執(zhí)行處理請求的任務(wù)的
  • 下面實現(xiàn)使用第一種節(jié)點,而且節(jié)點里面只有一個請求的id信息,這樣最簡單

    class Node {private int id;public Node(int id) {this.id = id;}@Overridepublic String toString() {return "Node{" +"id=" + id +'}';} } public class FCFSalgorithm {public static void main(String[] args) {Queue<Node> queue = new LinkedList<>();for (int i = 0; i < 10; i++) {queue.add(new Node(i));}while (!queue.isEmpty()) {Node poll = queue.poll();System.out.println("取出請求"+poll+"開始執(zhí)行任務(wù)");}} }

    優(yōu)先權(quán)排隊(Priority Queuing)

    為什么會出現(xiàn)優(yōu)先權(quán)呢,難道公平不好嗎,這是因為特權(quán)用戶確實充了錢,所以我們得優(yōu)先處理它的請求,還是用上面的節(jié)點只是增加了優(yōu)先級priority屬性,實現(xiàn)方式有很多種如下:

  • 最簡單的是使用一個數(shù)組,每次添加請求時按它的優(yōu)先級從小到大排序,(假設(shè)優(yōu)先級為0的優(yōu)先級最高),則我們每次取出請求就從數(shù)組下標(biāo)0取出來就行了,就是數(shù)組的添加操作會很麻煩
  • 可以使用一個鏈表,和數(shù)組一樣按優(yōu)先級從小到大排序,每次取出鏈表頭的請求執(zhí)行
  • 可以使用堆,不過堆的操作比較復(fù)雜,小頂堆的特點是頂點的值最小,所以其優(yōu)先級最高,可以每次把頂取出來,再重新構(gòu)造堆結(jié)構(gòu),再把頂取出來,再重新構(gòu)造,一直重復(fù)就可以組成一個排序數(shù)組了
  • 可以使用多個隊列,高優(yōu)先級的用戶進(jìn)入高優(yōu)先級隊列,低優(yōu)先級的用戶進(jìn)入低優(yōu)先級隊列,每次先從高優(yōu)先級隊列中取出元素,直到高優(yōu)先級隊列為空才從低優(yōu)先級隊列取出元素
    下面使用第三種方式,因為這樣添加請求最簡單,請求先找到屬于自己的隊列,在隊尾添加即可
  • class PNode {private int id;public int priority;public PNode(int id, int priority) {this.id = id;this.priority = priority;}@Overridepublic String toString() {return "PNode{" +"id=" + id +", priority=" + priority +'}';} }public class PriorityQueuingAlgorithm {public static void main(String[] args) {Queue<PNode>[] queueList = new Queue[3];for (int i = 0; i < 10; i++) {// 優(yōu)先級i % 3,則只有0,1,2三種優(yōu)先級PNode pNode = new PNode(i, i % 3);if (queueList[pNode.priority] == null) {queueList[pNode.priority] = new LinkedList<>();}Queue<PNode> queue = queueList[pNode.priority];queue.add(pNode);}for (Queue<PNode> queue : queueList) {while (!queue.isEmpty()) {PNode poll = queue.poll();System.out.println("取出請求"+poll+"開始執(zhí)行任務(wù)");}}} }

    循環(huán)排隊(Round Queuing)

    循環(huán)排隊也是公平的,為什么把不同的請求放入不同的隊列呢,可能因為它們屬于不同的類別,或者像我們排隊時可能有很多個窗口,每個窗口對應(yīng)一個隊列
    實現(xiàn):根據(jù)每個請求的節(jié)點的類別把它放入不同的列表,然后循環(huán)隊列列表每個隊列一次只取出一個請求執(zhí)行,然后輪到下一個隊列,如果一個隊列為空,直接跳到下一個隊列

    class RNode {private int id;public int type;public RNode(int id, int type) {this.id = id;this.type = type;}@Overridepublic String toString() {return "RNode{" +"id=" + id +", type=" + type +'}';} }public class RoundQueuingAlgorithm {public static void main(String[] args) {Queue<RNode>[] queueList = new Queue[3];for (int i = 0; i < 10; i++) {// 類型 i % 3,則只有0,1,2三種類型RNode rNode = new RNode(i, i % 3);if (queueList[rNode.type] == null) {queueList[rNode.type] = new LinkedList<>();}Queue<RNode> queue = queueList[rNode.type];queue.add(rNode);}while (true) {boolean flag = true;for (Queue<RNode> queue : queueList) {if (!queue.isEmpty()) {flag = false;RNode poll = queue.poll();System.out.println("取出請求"+poll+"開始執(zhí)行任務(wù)");}}if (flag) break;}} }

    加權(quán)公平排隊(Weighted Fair Queuing)

    回想一下我們上面的優(yōu)先級排隊,只有當(dāng)優(yōu)先級高的請求全部運行完了,才會運行下一優(yōu)先級的請求,這很明顯不符合社會主義核心價值觀,所以可以更加公平,讓氪金用戶不管氪多少,都只是增大他請求先運行的幾率,如果運氣好,普通用戶的請求也能在氪金用戶請求之前運行
    實現(xiàn)方式:
    仍然需要按優(yōu)先級把請求分到不同的隊列,每次也只拿出其中一個隊列的請求進(jìn)行處理,所以重點就在怎樣選擇這個隊列,有以下方式:

    加權(quán)輪詢

    根據(jù)用戶優(yōu)先級生成一個選擇列表,可以是一個數(shù)組,假如只有三個優(yōu)先級 0,1,2,那么數(shù)組可以為[0, 0, 0, 1, 1, 2] 這樣,表示先選擇三次0優(yōu)先級的隊列取出其中三個任務(wù)執(zhí)行,再選擇1優(yōu)先級的隊列取出其中兩個任務(wù)執(zhí)行,再選擇2優(yōu)先級的隊列取出其中一個任務(wù)執(zhí)行,如果0優(yōu)先級隊列沒有任務(wù)了,就找1優(yōu)先級隊列,如果1優(yōu)先級沒有了就找2優(yōu)先級隊列

    class WNode {private int id;public int priority;public WNode(int id, int priority) {this.id = id;this.priority = priority;}@Overridepublic String toString() {return "WNode{" +"id=" + id +", priority=" + priority +'}';} }public class WeightedFairQueuingAlgorithm {public static void main(String[] args) {Queue<WNode>[] queueList = new Queue[3];for (int i = 0; i < 10; i++) {WNode wNode = new WNode(i, i % 3);if (queueList[wNode.priority] == null) {queueList[wNode.priority] = new LinkedList<>();}Queue<WNode> queue = queueList[wNode.priority];queue.add(wNode);}// 可以根據(jù)優(yōu)先級種類數(shù)動態(tài)構(gòu)建的int[] dispatch = new int[]{0,0,0,1,1,2};while (true) {boolean flag = true;for (int index : dispatch) {Queue<WNode> queue = queueList[index];if (!queue.isEmpty()) {flag = false;WNode poll = queue.poll();System.out.println("取出請求"+poll+"開始執(zhí)行任務(wù)");}}if (flag) break;}} }

    加權(quán)隨機(jī)

    上面那種方式還是太固定了,對運氣好的普通用戶不公平,可以使用隨機(jī)數(shù),假設(shè)隨機(jī)數(shù)范圍為1-6,則隨機(jī)數(shù)是1-3三個數(shù)中一個,選擇0優(yōu)先級的隊列取出其中一個任務(wù)執(zhí)行,隨機(jī)數(shù)是4-5兩個數(shù)中一個,選擇1優(yōu)先級的隊列取出其中一個任務(wù)執(zhí)行,隨機(jī)數(shù)是6則選擇2優(yōu)先級的隊列取出其中一個任務(wù)執(zhí)行,也可以使用上面的數(shù)組,用隨機(jī)值作為下標(biāo)

    class WNode {private int id;public int priority;public WNode(int id, int priority) {this.id = id;this.priority = priority;}@Overridepublic String toString() {return "WNode{" +"id=" + id +", priority=" + priority +'}';} }public class WeightedFairQueuingAlgorithm {public static void main(String[] args) {Queue<WNode>[] queueList = new Queue[3];for (int i = 0; i < 100; i++) {WNode wNode = new WNode(i, i % 3);if (queueList[wNode.priority] == null) {queueList[wNode.priority] = new LinkedList<>();}Queue<WNode> queue = queueList[wNode.priority];queue.add(wNode);}Random random = new Random();int[] dispatch = new int[]{0,0,0,1,1,2};while (true) {boolean flag = true;int i = random.nextInt(6);int priority = dispatch[i];// 循環(huán)是為了當(dāng)隨到的高優(yōu)先級隊列為空,可以往低優(yōu)先級隊列找請求for (int j = priority; j < 3; j++) {Queue<WNode> queue = queueList[j];if (!queue.isEmpty()) {flag = false;WNode poll = queue.poll();System.out.println("取出請求"+poll+"開始執(zhí)行任務(wù)");// 取出一個請求,跳出內(nèi)循環(huán),繼續(xù)執(zhí)行外循環(huán)break;}j++;}// 只有當(dāng)隨機(jī)到最高優(yōu)先級,// 而且把往后所有優(yōu)先級都找遍都沒到到請求才退出循環(huán)if (priority == 0 && flag) break;}} }

    總結(jié)

    以上是生活随笔為你收集整理的Java 实现调度算法 包括 FCFS(FIFO)、优先权排队、循环排队、加权公平排队(WFQ)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。