通過這三次作業的訓練,初步掌握了多執行緒的設計方法。這三次作業讓我對這門課有了更深刻的認識,這門課的確是一門重課,不僅是大難度、高強度,還有它的永續性,吳際老師稱其為「崑崙課程」毫不為過。這是身體與心理的雙重礪煉。
本次作業模擬計程車的乘客呼叫與應答系統,訓練執行緒安全設計方法,同時應用物件導向分析方法和設計原則來開展分析和設計。
作業涉及的物件主要是地圖、計程車和計程車排程系統。乘客的請求從控制台輸入,乘客發出請求後,系統向以乘客為中心的4x4區域內的計程車廣播,收到廣播的計程車進行搶單,廣播有一定的時間視窗,視窗關閉後,系統從所有搶單的計程車中,根據計程車信用和計程車與乘客的距離來選擇一輛合適的計程車。計程車服務結束後,需要把此次服務的路徑、時間等資訊輸出到檔案中。
下面這張是這次作業的類圖。主要的類有計程車taxi類,排程scheduler類和地圖roadmap類。從執行緒的角度看,共有100個計程車執行緒,因請求而產生的排程執行緒,主排程執行緒,輸入處理執行緒和主線程。輸入處理執行緒負責接收控制台輸入並處理,主排程執行緒對每一請求建立乙個排程執行緒,排程執行緒在4x4區域廣播然後選擇一輛計程車,計程車服務結束後,排程執行緒輸出資訊,然後結束。執行緒之間的關係可以從後面的協作圖中看到。
roadmap可以儲存地圖,找出兩點間的最短路徑,判斷由某點向某個方向是否有路。路徑是乙個path物件,由方向+距離表示。作業中每條路的長度都相同,所以就省略了距離資訊,只記錄方向。path物件是不可變的,因此是執行緒安全的。整個程式裡只有乙個roadmap物件,但把它設計為不可變物件,因此也是執行緒安全的,不同的計程車可以同時呼叫shortestpath()方法。
由於要輸出計程車的軌跡,計程車某一時刻的狀態,為了管理這些資訊,分別用pathrecord物件和taxiinfo物件來記錄。pathrecord物件是可變的,可以新增新的軌跡。taxiinfo物件是不可變的。此外,不可變物件還有request物件,point物件,這些不可變物件都是執行緒安全的。
計程車類有serve(), wander(), rest(), takeorder()方法,分別對應計程車的服務,等待,停止,接單狀態。計程車執行緒主要與排程執行緒進行互動,因此,將執行緒協同與同步控制的重點放在計程車執行緒和排程執行緒的設計上。
圈複雜度最大值是13,主要來自於roadmap的構造方法和計程車類的run()方法。nestedblockdepth最大值是4,主要是兩層迴圈加上if-else巢狀導致的。總共有三處三層巢狀的**和三處兩層巢狀的**。
**總行數約是860行,其中taxi類,scheduler類和roadmap類各佔約200行。方法**總行數約570行,每個方法**行數最大值是30,平均值是6.2,方法總數是92個。
這次作業的bug是忽略了對出發地和目的地相同的請求的處理,以及計程車接單時正好在乘客的位置上的情況。這兩種情況都會導致在尋找最短路徑構造path物件時出現空指標。我認為導致問題出現的原因有如下:
作業指導書明確了出發地與目的地相同算作無效請求,可是在程式寫的過程中忘了這一點,寫完了之後沒有再看指導書,也沒有測試到。
對於每個請求,計程車有兩段路程,一是從計程車接單時位置到達乘客位置,二是從乘客位置到達目的地。指導書的要求保證了第二點不會出問題,而第一點是沒***的,所以需要在編碼時考慮到。
構造path物件時應該考慮到路徑為空的情況,但設計和實現的時候都沒有發現這個問題。
我認為這次寫的作業優點如下:
類的職責相對比較均衡。
缺點如下:
一些設計的效能上有提公升空間。例如尋找乘客周圍4x4區域的計程車,我使用的是對100個計程車都查詢一下的方法,其實可以做一些優化。
複雜度有些高。例如前面提到的計程車執行緒的run()方法,儘管沒有在run()方法裡面展開細節,可還是有多層迴圈或分支巢狀的情況。在寫的時候沒什麼感覺,現在再次回顧時一下子難以判斷出當時為什麼這麼寫,這麼寫對不對。
作業內容是實現乙個監控程式,針對給定監控範圍內的監控物件,以掃瞄方式探查監控物件相關屬性的變化,從而觸發規定的處理動作。監控範圍指計算機檔案系統中的一棵目錄樹,監控物件則是位於監控範圍內的具體檔案。處理動作包括恢復,記錄詳細資訊,記錄概要。作業的目標是訓練針對執行緒安全問題,如何平衡執行緒訪問控制和共享物件之間的矛盾。
從執行緒的角度上說,一條監控命令對應乙個監控執行緒,和乙個檔案掃瞄線程。monitor類能判斷監控物件的觸發器(包括重新命名,移動,大小改變,最後修改時間改變)是否觸發,並執行相應處理動作。snapshot類是檔案屬性的快照,它的結構就是一顆目錄樹。snapshotmanager是快照管理類,filescanner是檔案掃瞄線程,它建立快照並把快照交給snapshotmanager管理。analyzer類和taskperformer類分別是快照分析類和任務執行類,監控執行緒(monitor)從snapshotmanager中取出最近的快照,並交給analyzer分析,如果觸發,則讓taskperformer執行處理動作。summary和detail類是管理詳細資訊和概要的類,這些資訊會被定時寫到檔案中去。
snapshot物件是不可變的,它記錄有掃瞄時刻目錄下所有檔案的屬性,是乙個遞迴的結構,因此在分析快照時使用起來比較方便。tasktuple物件也是不可變的,記錄有一條監控命令對應的監控物件,觸發器及任務。summary類、detail類、snapshotmanager類都被設計為執行緒安全的類,因為所有的監控執行緒都共享同乙個summary和detail物件,可能同時被多個執行緒訪問,snapshotmanager在檔案掃瞄線程和監控執行緒間共享,也需要是執行緒安全的。safefile是執行緒安全的檔案訪問類。
巢狀深度最大值是5,共有1個4層巢狀和3個3層巢狀的**(方法內部)。巢狀深度最大值來自monitor的run()方法,迴圈和try-catch就佔了兩層,再加上if-else分支又佔了兩層,總共就是4層。其他幾個3層巢狀都上是一層迴圈加上兩層if-else。這種多層巢狀的**可讀性不強,正確性也難以判斷,所以要盡量避免。
所有屬性的個數是50,方法數是69,總**量約670行。每個方法**行數,平均值是6.4行,大部分在10-20行,有兩個方法是30來行。
這次作業的bug是,監控重新命名時,若同一目錄下有多個大小相同,最後修改時間相同的檔案,就會判斷出錯。判斷重新命名的標準是原來的檔案消失(絕對路徑找不到了),新增了乙個檔案,這個檔案的大小和最後修改時間與消失的檔案相同。我忽略了「新增」的要求,就出現了這個bug。
優點如下:
整體結構比較清晰。
達到了訓練執行緒安全,掌握如何平衡執行緒訪問控制和共享物件之間的矛盾的目標。
缺點如下:
使用了最簡單的方法來比較檔名,檔案路徑,其實可以用雜湊的方法來提高速度。
一些地方巢狀深度比較深,不易讀,容易出錯。
本次作業是設計一套由3部電梯組成的多電梯排程系統,通過採用執行緒機制,在第三次作業所實現程式的基礎上完成新的排程系統程式。電梯能夠支援捎帶,排程系統按照運動量均衡策略來排程樓層請求。
由於這次寫的程式類太多,類的關係錯綜複雜,就不給出類圖了。下面這張圖是乙個大體的結構,每個方框表示乙個物件,每個橢圓表示乙個放請求和取請求的托盤(因為第一次寫多執行緒程式不太熟悉,所以就顯式地用「托盤」來表示)。單個箭頭表示請求的流動方向,兩段都有箭頭的,是表示兩個執行緒間有互動。requestsimulator是請求模擬器,它從控制台中讀取輸入,產生請求。multischeduler是總的排程器,它負責將電梯直接請求分發給各部電梯,並且對樓層請求以捎帶和運動量均衡策略進行排程。再往下走是scheduler,它負責對單步電梯的排程,例如處理捎帶請求等等,這就歸約到了第三次作業的問題。
圈複雜度最大值是20,來自scheduler的排程方法。**總行數約1200行,方法總數是151個。可以發現後面兩次作業(6-7)沒有達到這麼大的規模,原因可能是電梯排程邏輯的複雜性。
此次作業bug主要有兩個。一是對輸入的處理上,一行多個空請求的處理與說明文件描述不符,是我疏於測試的問題,如果測試了就能夠發現。二是樓層請求的捎帶有問題,具體是什麼問題就沒有深究了,我猜測可能是邏輯上的問題加上對執行緒機制不熟悉的問題。
缺點如下:
邏輯混亂。例如排程器的排程方法,電梯的各種方法。一來是繼承前面兩次作業的設計導致難以修改,牽一髮而動全身。二來是加入了多執行緒後難以梳理出各部分的關係。
複雜度太高。高的複雜度導致容易出錯,難以測試,難以讀懂。
違背了很多設計原則例如ocp、lsp。
由於距第5次作業的時間比較久遠了,**寫得混亂,不忍直視,所以就簡略地分析一下。
物件導向程式設計第二次作業
1 第一次嘗試 剛看到大題目 a b 我首先想到的是簡單的a b的型別題。但認真看完題目發現沒有那麼簡單。必須在輸出的數的每三位加上逗號,這就需要劃分為三種情況了。首先我先在dev c 上嘗試進行 少量的資料嘗試發現好像無誤,然而 執行結果 測試結果為錯誤,仔細檢視發現選擇的語言沒有選擇為c語言。重...
第二次總結
距離上一次寫總結,過去了兩周,由於第四次任務不多,寫一篇部落格字數會很少,所以兩次任務一起寫一篇部落格。第四次任務 第四次的任務是做測試,並寫出測試文件。通過測試,把每個頁面都仔細的看了一遍,清楚了每個頁面要幹什麼,對這個專案想要實現什麼有了進一步的了解。對於我沒有及時把測試檔案發到群裡還反省了一番...
第二次總結
一 學習方面 二 生活方面 本週完成了歷史校外實踐活動,通過發放調查問卷調查了不同年齡段的人群對於歷史的興趣。三 感悟 在進行歷史校外實踐的時候,我們要發放調查問卷,很多人都配合我們的調查,並認真填寫,但也有人置之不理,做了一件事之後才知道這件事有多難做,所以以後在路上碰到需要幫忙調查問卷的人亦或是...