磁盤調度二
https://github.com/SKPrimin/HomeWork/tree/main/OperatingSystem/diskscan
實驗內容:編寫一個程序處理磁盤調度中尋道時間的策略。
實驗目的:磁盤調度中尋道時間直接影響到數據訪問的快慢,處理好磁盤尋道時間是關鍵。
實驗題目:
- 采用SCAN策略處理;
- 采用CSCAN策略處理;
實驗原理
掃描(SCAN)算法
進程“飢餓”現象
-
SSTF 算法雖然能獲得較好的尋道性能, 但卻可能導致某個進程發生“飢餓” (Starvation) 現象,其實質上是基於優先級的調度算法。因為只要不斷有新進程的請求到達, 且其所要訪問的磁道與磁頭當前所在磁道的距離較近,這種新進程的 I/O 請求必須優先滿足。對 SSTF 算法略加修改后所形成的 SCAN 算法, 即可防止老進程出現“飢餓”現象。
-
SCAN 算法(電梯調度算法)不僅考慮欲訪問的磁道與當前磁道的距離,更優先考慮磁 頭的當前移動方向。磁頭沿一個方向移動,直至該方向上無新的磁道訪問請求,才將磁臂換向,為反方向上的磁道訪問請求服務。
磁道距離 + 磁頭移動方向 -
優點:較好的尋道性能,且能防止進程飢餓
-
缺點:嚴重推遲某些進程的請求
循環掃描(CSCAN)算法
- Scan 算法的特例:磁頭剛移過某磁道 T ,該位置有訪問請求,但磁頭移動方向上不斷有新的請求,則磁道 T 上的訪問請求被嚴重推后。 改進SCAN算法方式:
- 磁頭單向移動
- 循環掃描
代碼實現
數據結構和符號說明
diskCollection
ArrayList類型數據,為初始的磁道號序列start
int類型數據,為磁道開始,默認向磁道號增加的方向訪問timeList
ArrayList類型數據,為訪問磁道對應的移動距離distanceSum
int類型數據,磁針尋道總道數diskList
ArrayList類型數據,為排序好的磁道訪問順序diskListBefore
ArrayList類型數據,為磁針優先訪問的磁道序列 由里向外訪問順序diskListAfter
ArrayList類型數據,為磁針后訪問的磁道序列 由外向里訪問順序
ScanDisk公共類
package com.process.diskscan;
import java.util.ArrayList;
/**
* @Author: SKPrimin
* @Date 2021/12/18 16:12
* @ClassName: ScanDisk
* @Description: TODO 掃描算法與循環掃描的公共類 定義變量結構和分組方法
*/
public class ScanDisk {
/**
* diskCollection ArrayList類型數據,為初始的磁道號序列
*/
protected ArrayList<Integer> diskCollection;
/**
* start int類型數據,為磁道開始,默認向磁道號增加的方向訪問
*/
protected int start;
/**
* timeList ArrayList類型數據,為訪問磁道對應的移動距離
*/
protected ArrayList<Integer> movList = new ArrayList<>();
/**
* distanceSum int類型數據,磁針尋道總道數
*/
protected int distanceSum;
/**
* diskList ArrayList類型數據,為排序好的磁道訪問順序
*/
protected ArrayList<Integer> diskList = new ArrayList<>();
/**
* diskListBefore ArrayList類型數據,為磁針優先訪問的磁道序列 由里向外訪問順序
*/
protected ArrayList<Integer> diskListBefore = new ArrayList<>();
/**
* diskListAfter ArrayList類型數據,為磁針后訪問的磁道序列 由外向里訪問順序
*/
protected ArrayList<Integer> diskListAfter = new ArrayList<>();
/**
* separate分割方法,以起始點為分界線,將磁道分為前后連個順序
*/
protected void separate() {
// 遍歷 diskCollection
for (int item : diskCollection) {
// 若在起始點外邊在第一輪訪問
if (item > start) {
diskListBefore.add(item);
// 在起始點里邊則在后一輪訪問
} else {
diskListAfter.add(item);
}
}
}
/**
* 計算距離函數通過三元運算符返回兩數絕對值
*
* @param a 一個位置
* @param b 另一個點位置
* @return 兩個位置之間的距離
*/
protected int distance(int a, int b) {
return a > b ? a - b : b - a;
}
/**
* 排序函數
*
* @param arrayList 要排序的數組列表
* @param reverse 是否逆序 false為升序,true為逆序
* @return 返回已經排序好的數組列表
*/
public ArrayList<Integer> sort(ArrayList<Integer> arrayList, boolean reverse) {
int len = arrayList.size();
for (int i = 0; i < len; i++) {
int index = i;
for (int j = i + 1; j < len; j++) {
// 若 reverse為false 升序排序 reverse為true則降序排序
if (!reverse) {
if (arrayList.get(j) < arrayList.get(index)) {
index = j;
}
} else {
if (arrayList.get(j) > arrayList.get(index)) {
index = j;
}
}
}
//位置交換 將較小reverse=false /較大reverse=true 的數提到前邊
int temp = arrayList.get(index);
arrayList.set(index, arrayList.get(i));
arrayList.set(i, temp);
}
return arrayList;
}
public void calculateTravelDistance() {
// 定義磁盤針頭
int pinhead = start;
// 計算訪問磁道號時的移動距離
for (int i = 0; i < diskList.size(); i++) {
// 將對應位置設置為距離 並統計總數
movList.add(distance(pinhead, diskList.get(i)));
distanceSum += movList.get(i);
pinhead = diskList.get(i);
}
}
}
SCAN實現類
package com.process.diskscan;
import java.util.ArrayList;
/**
* @Author: SKPrimin
* @Date 2021/12/18 16:08
* @ClassName: SCAN
* @Description: TODO 掃描算法的實現類
*/
public class SCAN extends ScanDisk {
/**
* 掃描算法構造器
*
* @param diskCollection 即將訪問的磁道號數組列表
* @param start 磁針起始點
*/
public SCAN(ArrayList<Integer> diskCollection, int start) {
this.diskCollection = diskCollection;
this.start = start;
}
/**
* 執行此次掃描算法的調動方法
*/
public void run() {
//調用父類的分類方法
separate();
// diskList接收排序好的順序
diskList = sort(diskListBefore, false);
diskList.addAll(sort(diskListAfter, true));
// 計算移動距離
calculateTravelDistance();
}
@Override
public String toString() {
return "\n掃描(SCAN)算法" +
"\n從" + start + "號磁道開始" +
"\n被訪問的下一個磁道號\t" + diskList +
"\n移動距離(磁道數)\t" + movList +
"\n總道數:" + distanceSum + "\t平均尋道長度:" + String.format("%.2f", (double) distanceSum / movList.size());
}
}
CSCAN實現類
package com.process.diskscan;
import java.util.ArrayList;
/**
* @Author: SKPrimin
* @Date 2021/12/18 17:24
* @ClassName: CSCAN
* @Description: TODO
*/
public class CSCAN extends ScanDisk {
/**
* 掃描算法構造器
*
* @param diskCollection 即將訪問的磁道號數組列表
* @param start 磁針起始點
*/
public CSCAN(ArrayList<Integer> diskCollection, int start) {
this.diskCollection = diskCollection;
this.start = start;
}
/**
* 執行此次掃描算法的調動方法
*/
public void run() {
//調用父類的分類方法
separate();
// diskList接收排序好的順序
diskList = sort(diskListBefore, false);
diskList.addAll(sort(diskListAfter, false));
// 計算移動距離
calculateTravelDistance();
}
@Override
public String toString() {
return "\n循環掃描(CSCAN)算法" +
"\n從" + start + "號磁道開始" +
"\n被訪問的下一個磁道號\t" + diskList +
"\n移動距離(磁道數)\t" + movList +
"\n總道數:" + distanceSum + "\t平均尋道長度:" + String.format("%.2f", (double) distanceSum / movList.size());
}
}
測試類
package com.process.diskscan;
import java.util.ArrayList;
/**
* @Author: SKPrimin
* @Date 2021/12/18 17:27
* @ClassName: Test
* @Description: TODO 基於掃描的磁盤調度算法
*/
public class Test {
public static void main(String[] args) {
// 磁盤號順序
int[] track = new int[]{55, 58, 39, 18, 90, 160, 150, 38,184};
ArrayList<Integer> ta = new ArrayList<>();
for (int t : track) {
ta.add(t);
}
// SCAN
SCAN ff = new SCAN( ta,100);
ff.run();
System.out.println(ff);
// CSCAN
CSCAN st = new CSCAN( ta,100);
st.run();
System.out.println(st);
}
}
運行截圖
python 實現
def scan(diskSet, needle):
print(f"\nSCAN\n從{needle}號磁道開始")
print(f"被訪問的下一個磁道號\t移動距離(磁道數)")
# 分割
diskListBefore = [x for x in diskSet if x > needle]
diskListAfter = [x for x in diskSet if x <= needle]
# 將列表排序 前升序 后降序
diskListBefore.sort()
diskListAfter.sort(reverse=True)
# 將后列表追加到前一列表
diskListBefore.extend(diskListAfter)
# 計算移動距離
distanceSum = 0
movdistan = []
# 計算訪問磁道號時的移動距離
for item in diskListBefore:
# 算出移動距離並保存
movdistan.append(abs(needle - item))
distanceSum += movdistan[-1]
# 更新磁針位置
needle = item
print(f"\t{item}\t\t{movdistan[-1]}")
print(f"\n總道數:{distanceSum}\t平均尋道長度:{distanceSum / len(movdistan)}")
def cscan(diskSet, needle):
print(f"\nCSCAN\n從{needle}號磁道開始")
print(f"被訪問的下一個磁道號\t移動距離(磁道數)")
# 分割
diskListBefore = [x for x in diskSet if x > needle]
diskListAfter = [x for x in diskSet if x <= needle]
# 將列表排序 前升序 后降序
diskListBefore.sort()
diskListAfter.sort()
# 將后列表追加到前一列表
diskListBefore.extend(diskListAfter)
# 計算移動距離
distanceSum = 0
movdistan = []
# 計算訪問磁道號時的移動距離
for item in diskListBefore:
# 算出移動距離並保存
movdistan.append(abs(needle - item))
distanceSum += movdistan[-1]
# 更新磁針位置
needle = item
print(f"\t{item}\t\t{movdistan[-1]}")
print(f"\n總道數:{distanceSum}\t平均尋道長度:{distanceSum / len(movdistan)}")
if __name__ == '__main__':
track = [55, 58, 39, 18, 90, 160, 150, 38, 184]
scan(track, 100)
cscan(track, 100)
python Other
import copy
# 掃描算法
def SCAN(seq, start, drct):
tempseq = copy.deepcopy(seq)
distance = 0
nownum = start
if drct == 0:
tempseq.sort()
i = 0
for i in range(len(tempseq)):
if tempseq[i] >= start:
break
templist = list(reversed(tempseq[:i]))
tempseq = tempseq[i:] + templist
for num in tempseq:
d = abs(nownum - num)
distance += d
nownum = num
print('被訪問的下一個磁道號:{} \t移動距離:{}'.format(num, d))
return distance / len(seq)
else:
tempseq.sort(reverse=True)
i = 0
for i in range(len(tempseq)):
if tempseq[i] <= start:
break
templist = list(reversed(tempseq[:i]))
tempseq = tempseq[i:] + templist
for num in tempseq:
d = abs(nownum - num)
distance += d
nownum = num
print('被訪問的下一個磁道號:{} \t移動距離:{}'.format(num, d))
return distance / len(seq)
# 循環掃描算法
def CSCAN(seq, start, drct):
tempseq = copy.deepcopy(seq)
distance = 0
nownum = start
if drct == 0:
tempseq.sort()
i = 0
for i in range(len(tempseq)):
if tempseq[i] >= start:
break
tempseq = tempseq[i:] + tempseq[:i]
for num in tempseq:
d = abs(nownum - num)
distance += d
nownum = num
print('被訪問的下一個磁道號:{} \t移動距離:{}'.format(num, d))
return distance / len(seq)
else:
tempseq.sort(reverse=True)
i = 0
for i in range(len(tempseq)):
if tempseq[i] <= start:
break
tempseq = tempseq[i:] + tempseq[:i]
for num in tempseq:
d = abs(nownum - num)
distance += d
nownum = num
print('被訪問的下一個磁道號:{} \t移動距離:{}'.format(num, d))
return distance / len(seq)
if __name__ == '__main__':
diskseq = input('請輸入需要訪問的磁道號序列(以空格分隔):')
# 55 58 39 18 90 160 150 38 184
diskseq = list(map(lambda x: int(x), diskseq.split()))
startnum = int(input('請輸入當前磁頭所在的磁道號:'))
direction = int(input('請輸入當前磁頭移動的方向(0表示自里向外,1表示自外向里):'))
print('-----------------掃描算法--------------------')
average_SCAN = SCAN(diskseq, startnum, direction)
print('平均尋道長度:', average_SCAN)
print('--------------------------------------------')
print('-----------------循環掃描算法--------------------')
average_CSCAN = CSCAN(diskseq, startnum, direction)
print('平均尋道長度:', average_CSCAN)
print('------------------------------------------------')