操作系統之基於掃描的磁盤調度 掃描(SCAN)算法 循環掃描(CSCAN)算法 java python實現


磁盤調度二

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);

    }
}
運行截圖

CSCAN運行效果截圖

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)

image

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('------------------------------------------------')



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM