OO第二單元總結

来源:https://www.cnblogs.com/cywuuuu/archive/2022/04/25/16192583.html
-Advertisement-
Play Games

OO第二單元電梯總結 架構模式 Hw5, Hw6, Hw7三次作業架構基本沒有巨大變化,屬於增量的疊加開發 hw5 一級生產者消費者模型with策略類分離 第一次作業, 我做了兩種架構的嘗試, 寫了: 調度線程祭天型 單托盤 帶調度器線程的兩級托盤 在嘗試寫了兩種架構的基礎上, 我分析了一下兩種架構 ...


OO第二單元電梯總結

目錄

架構模式

Hw5, Hw6, Hw7三次作業架構基本沒有巨大變化,屬於增量的疊加開發

hw5 一級生產者消費者模型with策略類分離

image

第一次作業, 我做了兩種架構的嘗試, 寫了:

  1. 調度線程祭天型 單托盤

    image

  2. 帶調度器線程的兩級托盤

image

在嘗試寫了兩種架構的基礎上, 我分析了一下兩種架構,

  1. 不對任何數據進行區分, 所有數據對電梯可見

  2. 是二級生產者消費者模型, 僅僅對每個樓進行劃分,每棟樓之間的請求隔離, 樓內請求電梯間是互通的

在我的兩種架構里, 第二種架構的scheduler線程僅僅負責取總托盤的請求,然後按樓區分發。本質上和你電梯直接去查找大托盤, 各取所需, 在功能上似乎沒有任何區別。 反而調度祭天,減少了一個線程, 首先會簡單不少, 其次, 每個電梯可見所有請求, 或許擴展性反而更好, 所以最終我選擇了1作為三次作業的基本架構。

總之,對於架構的選擇取捨就是:

要獲取高效簡潔解決問題的架構, 就得在調度自由度和懶癌(bushi, 簡單度之間做取捨

​ ————沃茲基朔德

image

關於策略類的提取:

​ 體現了DIP依賴倒置原則高級模塊不應該依賴低級模塊,而是依賴抽象介面,通過抽象介面使用對應的低級模塊

關於優化實現了:
  1. 量子電梯, 通過記錄上次arrive & close 時間, 減少了wait以後,再被喚醒,可以快速的度過本層(其實就是拿一部分沉睡時間當作運動中的時間)比如:

        private void moveArrive() {
            try {
                
                Thread.sleep(max(400 + (lastArriveTime - System.currentTimeMillis()), 0));
                // Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            building = (building + dir + 5) % 5;
            // arrive
            MyOutput.println("ARRIVE-" + buildingNameList[building] + "-" +
                    floor + "-" + elevatorId);
        }
    
  2. 開關門400ms恆定保持

  3. 先下後上,儘量哆啦人(這不是共識嗎?但我和其他童鞋交流時發現他沒有,姑且算是吧

hw6 增加了兩個電梯子類的一級生產者消費者模型

image

這次作業中, 可以看到最令人神奇的就是:

  • 加入了橫向電梯
  • 動態新增電梯
  • 不考慮換乘

這就意味著我們要為環形電梯設計新的的調度策略, 同時多個電梯這一次終於可以互相進行搶人, 這就帶來了競爭和分配如何選擇的問題

  1. 對於新增橫豎電梯,還存在行為上的差異, 所以我搞了兩個子類, 分別處理橫豎方向的電梯

  2. 動態新增電梯, 這裡其實暗示我們搞線程池, 然鵝我也現在才發現, 如果以後有機會可以搞個線程池, 其次由於選擇了調度線程寄了天, 自然選擇

  3. 提前為換乘打餘量,我將托盤中的PersonRequest 改成了ConcurrentLinkedQueue<PersonRequest>鏈表,具體怎麼換乘hw7來說

  4. 環形電梯調度策略:

    採用了類ALS基準策略, 效果還可以, 基本性能分都拿到了, 98+不戳的

    Look也寫了,但是擔心出bug, 所以沒有採取這個策略對象, 用了ALS, 當然Look肯定寫好了是更快的

hw7 帶換乘的一級生產者消費者模型

image

可以看到基本沒改什麼, 就是在Input類中加入了一個換乘拆分函數

image

線程的協作簡圖

image

主要就是

  • 輸入線程,接收到輸出, 進行請求拆分, 或者創建電梯線程
  • 電梯線程, 在while迴圈中, 每次檢測是否wait或者return, 此後決定上下人,並依據上下人開關門, 最後決定方向並前進

同步塊和鎖

總結分析三次作業中同步塊的設置和鎖的選擇,並分析鎖與同步快中處理語句之間的關係

三次作業架構基本保持了一致, 且同步塊基本也保持了一致, 取最後一次作業的同步塊講解:

首先是 RequestTable.java中

// InputHandler 添加請求, Elevator送人到中轉站時
public synchronized void addRequest(ConcurrentLinkedQueue<PersonRequest> a) {
        requests.add(a);
    }
// personLeft維護的是 沒有送達目的地的人數
// InputHandler接收到請求時
    public synchronized void addPersonLeft() {
        this.notifyAll(); 
        personLeft++;
    }
// Elevator送人到目的地
    public synchronized void subPersonLeft() {
        personLeft--;
    }
// 輸入結束
    public synchronized boolean isInputEnd() {
        return inputEnd;
    }
// 輸入結束
    public synchronized void setInputEnd(boolean inputEnd) {
        this.notifyAll(); 
        this.inputEnd = inputEnd;
    }

// 上下是否沒有請求了
    public synchronized boolean isUpDownEmpty(String buildingName) {
   		...
    }
// 同理
    public synchronized boolean isLeftRightEmpty(int floor) {
        ...
    }
// 前方是否有請求
    public synchronized boolean upDownRequestAhead(String buildingName, int floor, int velocity) {
		...
    }
// 人都送到了
    public synchronized boolean noPersonLeft() {
        return personLeft == 0;
    }


Strategy類木有鎖, 不互斥的給出運動方向、上下人

public interface Strategy {
    public Vector<PersonRequest> getPickUpRequests(Vector<ConcurrentLinkedQueue<PersonRequest> inside,
                                                   int floor, int dir, int capLeft);

    public boolean turnAround(Vector<ConcurrentLinkedQueue<PersonRequest> inside, int floor, int dir, int capacity);

}

InputHandler中的鎖:

// 用於判停,判wait   
private boolean checkWaitReturn() {
        synchronized (requestTable) {
            while (this.isempty() && requestTable.isLeftRightEmpty(floor)) {
                if (requestTable.isInputEnd() &&
                        requestTable.isLeftRightEmpty(floor) && requestTable.noPersonLeft()
                        && this.isempty()) {
                    requestTable.notifyAll();
                    return true;
                }
                try {
                    requestTable.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

主要就是鎖住了RequestTable 防止 check & modify, read & write, write&write 的線程危險, 使得其互斥。

還有就是電梯在運行時需要查看一下情況,其實也可以放在RequestTable類里。

調度器設計

hw5的一個版本里, 我的調度器主要就是負責按樓層分發, 沒有任何特殊性,感覺名存實亡就是擺設, 所以就捨棄了調度器線程。

我的調度器線程沒了, 調度主要就是自由競爭。

同時換乘請求拆分時, 優化了一部分基準策略, 按概率隨機分配拆分樓層, 使得拆分樓層分佈保持較為均勻

bug與測試 總結

強測&互測bug

三次作業總共出現了一個bug, 就是我第一次作業最後提交的時候一著急, 不小心把上下人邏輯搞錯了, 導致可以承載的人數過多,wa了好幾個點,真的心痛, 血的教訓。

debug最重要的是按部就班的按debug流程來, 不要著急,不能東一榔頭西一棒槌,都可能錯過你的bug.

ps: 中測真的很弱, 感覺就是把你騙進來殺

​ ————沃茲基朔德

比如在那以後我就規定了這麼一套流程,防止我心急或者漏了什麼,導致bug被miss過去, 看著圖一樂吧,畢竟我真是太粗了, 這些流程守好了, 別丟東西了

遇到的記憶深刻的bug

image

本地測試與測評機

測評機三次作業都做了, 還和小伙伴一塊分享一塊測試, 真不戳!評測機也是不斷迭代hhh

從最開始只能測一個人,到支持多個人一起pk速度

唯一不足就是對於超時應該及時掐斷, 我還沒來及整, python多線程有時間學一波吧

心得體會

線程安全心得

線程安全的心得在於,關鍵在於設計線程安全類, 通過線程安全類來保證各個線程的行為是安全的, 比如通過鎖的方法保證互斥, 通過資源也同時完成了線程間的協作通信。 關鍵在於選取合適的臨界區, 保證線程安全的情況下儘量小。

層次化設計&設計原則

三次作業基本是迭代的, 每次作業都在上次的作業上或是繼承, 或是新增了一些功能, 較好的實現了代碼復用

SRP: 職責應該單一,不要承擔過多的職責。體現在每個類只負責自己的行為, 比如:

​ 電梯只負責開關門, 上下人, 停止, 轉向, 前進。

​ RequestTable僅僅負責,根據電梯的信息進行搜索並返回數據,以及數據的更刪查改。

​ InputHandler僅僅負責拿到請求、處理請求

OCP:修改軟體功能的時候,使得他不能修改我們原有代碼,只能新增代碼實現軟體功能修改的目的。 可以從三次代碼的結構是迭代的, 僅僅新增了部分代碼, 實現代碼復用。

ISP: 介面的內容一定要儘可能地小,能有多小就多小。 我將策略類的介面僅設置了2個方法,轉向、上下人,最小限度的保持了策略類對電梯的控制

LSP, DIP: 體現在策略類的分離體現了 ,前面說過了,就不重覆了

真情實感

做首詩紀念一下

電梯月

​ ——cywuuuu

歡送電梯月,

可惜有bug。

下次再努力,

爭取bugfree!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 解釋器模式是什麼 解釋器是一種行為型設計模式,指給分析對象定義一個語言,並定義該語言的文法表示,再設計一個解析器來解釋語言中的句子。也就是說,用編譯語言的方式來分析應用中的實例。這種模式實現了文法表達式處理的介面,該介面解釋一個特定的上下文。 為什麼用解釋器模式 在軟體開發中,會遇到有些問題多次重覆 ...
  • 訪問者模式是什麼 訪問者是一種行為型設計模式, 允許你在不修改已有代碼的情況下向已有類層次結構中增加新的行為。 為什麼用訪問者模式 訪問者模式建議將新行為放入一個名為訪問者的獨立類中,而不是試圖將其整合到已有類中。現在需要執行操作的原始對象將作為參數被傳遞給訪問者中的方法, 讓方法能訪問對象所包含的 ...
  • 有了《系統架構的11條原則》,真正到設計階段還有另外11個考慮。 系統正確性 考慮一:負負得正 假如我們看到某個代碼,明顯有邏輯錯誤,想隨手改改。你就要考慮一件事情:這段明顯有問題的代碼為什麼線上上運行著沒有人來報bug?有一種正常運行叫做【負負得正】。如果把錯誤的邏輯改對了反而可能引起問題。 這種 ...
  • 組織管理模塊屬於SaaS產品非常底層的架構,非常考驗架構能力,幾乎所有的業務場景都需要應用組織數據,背後反應的是企業決策層的經營戰略和財務戰略,因此需要掌握一定的企業管理知識和財務知識,如果能夠掌握組織管理的概念和要點,對設計好SaaS產品幫助巨大。 ...
  • 如果軟體系統存在持續的迭代周期,那麼其中業務、技術、架構的複雜性都會直線拉升,其相應的開發難度也會提高,隨之而來的壓力會持續在開發和測試之間來回橫跳。 ...
  • 鑒於上一篇中最後三個問題: 1、上述程式是否能進行優化(比如功能相同的) 2、創建三個3個實例,用了3個語句,能否建一個函數,只輸入一個數n,就自動創建n個實例?同時,每個實例的num_times隨機,(n比較大時,num_times應該比較小) 3、當實現上述功能後,程式運行,只輸入一個參數(創建 ...
  • L1-081 今天我要贏 #include <iostream> using namespace std; int main() { cout << "I'm gonna win! Today!\n2022-04-23"; } 2018 年我們曾經出過一題,是輸出“2018 我們要贏”。今年是 20 ...
  • 隨著短視頻的大火,不僅可以給人們帶來娛樂,還有熱點新聞時事以及各種知識,刷短視頻也逐漸成為了日常生活的一部分。本文以一個簡單的小例子,簡述如何通過Pyhton依托Selenium來爬取短視頻,僅供學習分享使用,如有不足之處,還請指正。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...