數據結構和算法專題---5、調度算法與應用

本章我們會對調度算法做個簡單介紹,包括常用的調度算法(FCFS、SJF、RR、HPF)的概述、實現方式、典型場景做個說明。

什么是調度算法

調度算法常見于操作系統中,因為系統資源有限,當有多個進程(或多個進程發出的請求)要使用這些資源時,就必須按照一定的原則選擇進程(請求)來占用資源。這就是所謂的調度。在現實生活中也是一樣,比如會議室的占用。

先來先服務(FCFS)

概念

先來先服務,很好理解,就是按照服務提交申請的順序,依次執行。講究先來后到。

實現

定義一個Task類作為任務實例,BlockingQueue作為服務隊列

package com.ls.cloud.sys.alg.schedule;/*** 任務類*/
public class Task {//任務名稱private String name;//任務提交的時間private Long addTime;//任務的執行時間private int servTime;//任務優先級private int level;public Task(String name, int servTime) {this.name = name;this.servTime = servTime;this.addTime = System.currentTimeMillis();}public Task(String name, int servTime,int level) {this.name = name;this.servTime = servTime;this.level = level;this.addTime = System.currentTimeMillis();}public void execute() {try {// !重點:執行時睡眠,表示該任務耗時servTime毫秒Thread.currentThread().sleep(servTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(String.format("execute:name=%s,level=%s,addTime=%s,servTime=%s",name,level, addTime, servTime));}
}
package com.ls.cloud.sys.alg.schedule;import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;public class FCFS {public static void main(String[] args) throws InterruptedException {//阻塞隊列,FCFS的基礎final LinkedBlockingQueue<Task> queue = new LinkedBlockingQueue(5);//服務線程,任務由該線程獲取和執行new Thread(new Runnable(){@Overridepublic void run() {while (true) {try {queue.take().execute();} catch (Exception e) {e.printStackTrace();}}}}).start();//向隊列中每隔100ms防入一個任務for (int i = 0; i < 5; i++) {System.out.println("add task:"+i);queue.put(new Task("task"+i,new Random().nextInt(1000)));}}}

結果

add task:0
add task:1
add task:2
add task:3
add task:4
execute:name=task0,level=0,addTime=1701829693127,servTime=67
execute:name=task1,level=0,addTime=1701829693127,servTime=593
execute:name=task2,level=0,addTime=1701829693127,servTime=903
execute:name=task3,level=0,addTime=1701829693127,servTime=719
execute:name=task4,level=0,addTime=1701829693127,servTime=283
  • add按順序放入,時間有序
  • execute也按時間順序執行,而不管后面的servTime,也就是不管執行任務長短,先來先執行

優缺點

  • 多應用于cpu密集型任務場景,對io密集型的不利。
  • 時間相對均衡的業務可以排隊處理,比如現實中排隊打卡進站。
  • 如果業務需要依賴大量的外部因素,執行時間片長短不一,FCFS算法不利于任務的整體處理進度,可能會因為一個長時間業務的阻塞而造成大量等待。

短作業優先 (SJF)

概念

執行時間短的優先得到資源。即執行前申報一個我需要占據cpu的時間,根據時間長短,短的優先被調度。我不占時間所以我先來。

實現

使用TreeMap可以實現優先級的任務排序。

package com.ls.cloud.sys.alg.schedule;import javax.swing.text.html.parser.Entity;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;public class SJF {public static void main(String[] args) throws InterruptedException {//有序Map,將服務時間作為key排序final TreeMap<Integer,Task> treeMap = new TreeMap();//向隊列中放入5個任務for (int i = 0; i < 5; i++) {System.out.println("add task:"+i);int servTime = new Random().nextInt(1000);//注意,key是servTime,即執行預估時間treeMap.put(servTime,new Task("task"+i,servTime));}//服務線程,任務由該線程獲取和執行new Thread(new Runnable(){@Overridepublic void run() {while (true) {try {//有序Map中,服務時間短的,置于頂部,那么自然就會優先被取出Map.Entry<Integer,Task> entry = treeMap.pollFirstEntry();if (entry == null){Thread.currentThread().sleep(100);}else {entry.getValue().execute();}} catch (Exception e) {e.printStackTrace();}}}}).start();}
}

結果

add task:0
add task:1
add task:2
add task:3
add task:4
execute:name=task2,level=0,addTime=1701842880485,servTime=503
execute:name=task1,level=0,addTime=1701842880485,servTime=622
execute:name=task4,level=0,addTime=1701842880485,servTime=862
execute:name=task3,level=0,addTime=1701842880485,servTime=941
execute:name=task0,level=0,addTime=1701842880485,servTime=952

  • add任務有序,確實按照從前往后順序提交的
  • execute任務無序,按servtime排序,說明執行時間段的得到了優先執行

優缺點

  • 適用于任務時間差別較大的場景,仍然以進站為例,拿出公交卡的優先刷卡,還沒辦卡的讓一讓。
  • 解決了FCFS整體處理時間長的問題,降低平均等待時間,提高了系統吞吐量。
  • 未考慮作業的緊迫程度,因而不能保證緊迫性作業(進程)的及時處理
  • 對長作業的不利,可能等待很久而得不到執行
  • 時間基于預估和申報,主觀性因素在內,無法做到100%的精準

時間片輪轉(RR)

概念

時間片逐個掃描輪詢,輪到誰誰執行。大家公平裁決來者有份,誰也別插隊。像是棋牌游戲中的發牌操作,做到了時間和機會上的平均性。

實現

基于數組做為數據插槽方式實現。

package com.ls.cloud.sys.alg.schedule;import java.util.Random;public class RR {//定義數組作為插槽,每個插槽中可以放入任務Integer[] integers;//length插槽的個數public RR(int length){integers = new Integer[length];}//將任務放入插槽public void addTask(int value){int slot = 0;//不停查找空的插槽while (true) {//發現空位,將當前任務放入if (integers[slot] == null){integers[slot] = value;System.out.println(String.format("------------------------->add task index=%s,value=%s",slot,value));break;}//如果當前位置有任務占用,看下一個位置slot++;//如果插槽遍歷完還是沒有空位置,那么從頭開始再找,繼續下一個輪回if (slot == integers.length){slot = 0;}}}//執行任務。輪詢的策略就在這里public void execute(){//開啟一個線程處理任務。在現實中可能有多個消費者來處理new Thread(new Runnable() {@Overridepublic void run() {int index = 0;while (true) {//指針輪詢,如果到達尾部,下一步重新轉向開頭// 數據物理結構是一個數組,邏輯上是一個環if (index == integers.length){index = 0;}//如果當前位置沒有任務,輪詢到下一個插槽if (integers[index] == null){index++;continue;}else{//隨機等待,表示模擬當前任務有一個執行時間try {Thread.currentThread().sleep(new Random().nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}//模擬任務執行的內容,也就是打印一下當前插槽和里面的值System.out.println(String.format("execute index=%s,value=%s",index,integers[index]));//執行完,將當前插槽清空,騰出位置來給后續任務使用integers[index] = null;}}}}).start();}public static void main(String[] args) {//測試開始,定義3個插槽RR rr = new RR(3);//喚起執行者線程,開始輪詢rr.execute();//放置10個任務for (int i = 0; i < 10; i++) {rr.addTask(i);}}
}

結果

------------------------->add task index=0,value=0
------------------------->add task index=1,value=1
------------------------->add task index=2,value=2
execute index=0,value=0
------------------------->add task index=0,value=3
execute index=1,value=1
------------------------->add task index=1,value=4
execute index=2,value=2
------------------------->add task index=2,value=5
execute index=0,value=3
execute index=1,value=4
------------------------->add task index=1,value=6
------------------------->add task index=0,value=7
execute index=2,value=5
------------------------->add task index=2,value=8
execute index=0,value=7
execute index=1,value=6
------------------------->add task index=1,value=9
execute index=2,value=8
execute index=1,value=9
  • add任務index無序,value有序,說明是按順序提交的,但是插槽無序,哪里有空放哪里
  • execute執行index有序value無序,說明任務是輪詢執行的,每個插槽里的任務不一定是誰

優缺點

  • 做到了機會的相對平均,不會因為某個任務執行時間超長而永遠得不到執行
  • 缺乏任務主次的處理。重要的任務無法得到優先執行,必須等到時間片輪到自己,著急也沒用

優先級調度(HPF)

概述

進程調度每次將處理機分配給具有最高優先級的就緒進程。最高優先級算法可與不同的CPU方式結合形成可搶占式最高優先級算法和不可搶占式最高優先級算法。

實現

在Task類中新增一個屬性level作為優先級標識

package com.ls.cloud.sys.alg.schedule;/*** 任務類*/
public class Task {//任務名稱private String name;//任務提交的時間private Long addTime;//任務的執行時間private int servTime;//任務優先級private int level;public Task(String name, int servTime) {this.name = name;this.servTime = servTime;this.addTime = System.currentTimeMillis();}public Task(String name, int servTime,int level) {this.name = name;this.servTime = servTime;this.level = level;this.addTime = System.currentTimeMillis();}public void execute() {try {// !重點:執行時睡眠,表示該任務耗時servTime毫秒Thread.currentThread().sleep(servTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(String.format("execute:name=%s,level=%s,addTime=%s,servTime=%s",name,level, addTime, servTime));}
}
package com.ls.cloud.sys.alg.schedule;import java.util.Map;
import java.util.Random;
import java.util.TreeMap;public class HPF {public static void main(String[] args) throws InterruptedException {//有序Map,將服務優先級作為key排序final TreeMap<Integer, Task> treeMap = new TreeMap();//向隊列中放入5個任務for (int i = 0; i < 5; i++) {System.out.println("add task:" + i);int servTime = new Random().nextInt(1000);//注意放入的key,是優先級,這里用i標識treeMap.put(i, new Task("task" + i, servTime,i));}//服務線程,任務由該線程獲取和執行new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {//有序Map中,優先級最高的,在底部部,那么自然就會優先被取出Map.Entry<Integer, Task> entry = treeMap.pollLastEntry();if (entry == null) {Thread.currentThread().sleep(100);} else {entry.getValue().execute();}} catch (Exception e) {e.printStackTrace();}}}}).start();}
}

結果

add task:0
add task:1
add task:2
add task:3
add task:4
execute:name=task4,level=4,addTime=1701843942807,servTime=452
execute:name=task3,level=3,addTime=1701843942807,servTime=433
execute:name=task2,level=2,addTime=1701843942807,servTime=196
execute:name=task1,level=1,addTime=1701843942807,servTime=166
execute:name=task0,level=0,addTime=1701843942806,servTime=97
  • 按0-4順序加入task
  • 執行時,按4-0,優先級高的先得到執行,而與服務時間,加入的時間無關

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210607.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210607.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210607.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Oracle 怎樣修改DB_NAME

DBNEWID 是一個數據庫實用程序&#xff0c;用于更改 Oracle 數據庫的 DBNAME 和 DBID。可以更改 DBID 或 DBNAME 或兩者。 DBNAME 是在創建數據庫時指定的數據庫名稱&#xff0c;DBID 是創建數據庫時分配給數據庫的唯一編號。 以下步驟演示如何使用 DBNEWID 實用程序更改 Oracl…

【論文閱讀筆記】序列數據的數據增強方法綜述

【論文閱讀筆記】序列數據的數據增強方法綜述 摘要 這篇論文探討了在深度學習模型中由于對精度的要求不斷提高導致模型框架結構變得更加復雜和深層的趨勢。隨著模型參數量的增加&#xff0c;訓練模型需要更多的數據&#xff0c;但人工標注數據的成本高昂&#xff0c;且由于客觀…

將RK3399的挖掘機開發板在Android10下設置系統默認為24小時制

將RK3399的挖掘機開發板在Android10下設置系統默認為24小時制 2023/12/9 22:07 應該也可以適用于RK3399的Android12系統 --- a/frameworks/base/packages/SettingsProvider/res/values/defaults.xml b/frameworks/base/packages/SettingsProvider/res/values/defaults.xml -2…

MagicAnimate

簡介 新加坡國立大學 Show 實驗室和字節聯合做了一項類似的研究。他們提出了一個基于擴散的框架 MagicAnimate&#xff0c;旨在增強時間一致性、忠實地保留參考圖像并提升動畫保真度。并且&#xff0c;MagicAnimate 項目是開源的&#xff0c;目前推理代碼和 gradio 在線 demo …

python程序大全(9)——鼠標亂動惡搞小病毒(有資源)

目錄 &#x1f3c6;一、前言 &#x1f3c6;二、程序第一版 &#x1f3c6;三、程序大魔改 &#x1f6a9;1、基礎改動 &#x1f6a9;2、打包 &#x1f6a9;3、F12保護機制 &#x1f6a9;4、添加開機自啟項 &#x1f6a9;5、自己也不懂的線程魔改 &#x1f3c6;四、最終代碼 &…

排列游戲 --- 動態規劃 --- 題解

目錄 排列游戲 題目描述 輸入描述: 輸出描述: 輸入 輸出 備注: 思路&#xff1a; 代碼&#xff1a; 排列游戲 K-排列游戲_牛客競賽動態規劃專題班習題課 (nowcoder.com) 時間限制&#xff1a;C/C 1秒&#xff0c;其他語言2秒 空間限制&#xff1a;C/C 262144K&#…

外包干了三年,我承認我確實廢了……

沒錯&#xff0c;我也干過外包&#xff0c;一干就是三年&#xff0c;三年后&#xff0c;我廢了…… 雖說廢的不是很徹底&#xff0c;但那三年我幾乎是出差了三年、玩了三年、荒廢了三年&#xff0c;那三年&#xff0c;我的技術能力幾乎是零成長的。 說起這段三年的外包經歷&a…

vue中滾輪縮放事件

在Vue中&#xff0c;可以使用原生JS的滾輪事件監聽來實現滾輪縮放&#xff1a; 首先在模板中給需要監聽滾輪事件的元素添加一個ref屬性&#xff0c;用于在Vue中獲取元素節點。 <template><div ref"scale"><!-- 需要縮放的內容 --></div> &…

Ubuntu中編譯出Windows的可執行程序(.exe)

1、前言 在嵌入式開發中&#xff0c;交叉編譯是很常見的情況&#xff0c;如果你把Windows電腦也看做一塊高性能的開發板&#xff0c;那在Ubuntu中編譯出Windows上運行的可執行程序也是很好理解的行為。 2、安裝mingw64環境 sudo apt-get install mingw-w64 3、測試編譯鏈是否安…

【力扣100】5.盛水最多的容器

添加鏈接描述 我的題解&#xff1a; class Solution:def maxArea(self, height: List[int]) -> int:# 兩層for循環&#xff0c;保存最大值temp0res0for i in range(len(height)-1):for j in range(i1,len(height)):tempmin(height[i],height[j])*(j-i)# print(temp)resmax…

Linux壓縮命令tar之排除不需要的文件或者目錄(--exclude)

tar 中–exclude的簡單用法 # 首先創建一個如下的目錄結構和測試文件 mydir/ ├── myfile ├── zidir1 │ ├── file1 │ └── file2 ├── zidira │ └── filea └── zidirA├── fileA└── fileB3 directories, 6 files# 上面在 mydir 目錄下有三個子…

C++知識點總結(8):尺取法

尺取法 一、復習枚舉算法1. 算法三要素2. 最小公倍數公式3. 時間復雜度 二、算法優化初級1. 概念2. 例題(1) 最長小寫子串Ⅰ 初步算法Ⅱ 認識尺取法Ⅲ 尺取法程序 (2) 最長遞增子串(3) 最小子串和Ⅰ 偽代碼Ⅱ 完整代碼 (4) 最短字符串包含Ⅰ 偽代碼 Ⅱ 代碼 一、復習枚舉算法 …

打破常規思維:Scrapy處理豆瓣視頻下載的方式

概述 Scrapy是一個強大的Python爬蟲框架&#xff0c;它可以幫助我們快速地開發和部署各種類型的爬蟲項目。Scrapy提供了許多方便的功能&#xff0c;例如請求調度、數據提取、數據存儲、中間件、管道、信號等&#xff0c;讓我們可以專注于業務邏輯&#xff0c;而不用擔心底層的…

MongoDB簡介與安裝

目錄 1. MongoDB簡介 2. 安裝MongoDB 3. 基本命令行操作 4. Java代碼實踐 MongoDB是一種NoSQL數據庫&#xff0c;以其靈活的文檔存儲模型和高度可擴展性而聞名。這篇文章將簡單介紹一下MongoDB的基本概念&#xff0c;包括其特點和優勢&#xff0c;并提供安裝MongoDB的步驟。…

MapReduce的執行過程(以及其中排序)

Map階段(MapTask)&#xff1a; 切片(Split)-----讀取數據(Read)-------交給Mapper處理(Map)------分區和排序(sort) Reduce階段(ReduceTask): 拷貝數據(copy)------排序(sort)-----合并(reduce)-----寫出(write) 1、Map task讀取&#xff1a; 框架調用InputFormat類的子類讀取…

Vue2與Vue3的語法對比

Vue2與Vue3的語法對比 Vue.js是一款流行的JavaScript框架&#xff0c;通過它可以更加輕松地構建Web用戶界面。隨著Vue.js的不斷發展&#xff0c;Vue2的語法已經在很多應用中得到了廣泛應用。而Vue3于2020年正式發布&#xff0c;帶來了許多新的特性和改進&#xff0c;同時也帶來…

rpc原理與應用

IPC和RPC&#xff1f; RPC 而RPC&#xff08;Remote Procedure Call&#xff09;&#xff0c;又叫做遠程過程調用。它本身并不是一個具體的協議&#xff0c;而是一種調用方式。 gRPC 是 Google 最近公布的開源軟件&#xff0c;基于最新的 HTTP2.0 協議&#xff0c;并支持常見…

【SQLite】SQLite3約束總結

前面學習了SQLite數據庫的常見使用方法&#xff0c;其中包含許多約束&#xff0c;常見的如NOT NULL、DEFAULT、UNIQUE、PRIMARY KEY&#xff08;主鍵&#xff09;、CHECK等 本篇文章主要介紹這些約束在SQLite中的使用 目錄 什么是約束NOT NULL 約束DEFAULT約束UNIQUE約束PRIMA…

【設計模式-3.2】結構型——適配器模式

說明&#xff1a;本文介紹設計模式中結構型設計模式中的&#xff0c;適配器模式&#xff1b; 插頭轉換器 適配器模式屬于結構型設計模式&#xff0c;設計思想體現在結構上的。以插頭轉換器為例&#xff0c;當你需要給手機充電&#xff0c;但是眼前只有一個三孔插座&#xff0…

Java基本類型的高級使用方法詳解

引言 Java中的基本數據類型&#xff08;primitive types&#xff09;是構建程序的基礎&#xff0c;包括整型、浮點型、字符型、布爾型等。除了直接使用這些基本類型外&#xff0c;Java還提供了一些高級的使用方法&#xff0c;使得我們能夠更靈活地處理基本類型數據。本文將深入…