工作隨筆2010/10/14(感悟,問題及學習)

[size=medium]
這段時間在Code Review之餘負責一個處理大數據量程序的正常運行。本應該是國慶之前完成的事,但因對程序處理能力的認識不足就拖到了現在。程序由單線程改造爲併發,並因此修改當初的設計,後來針對出現的問題做持續的處理及優化。下面列出在完成這個任務時所想到的及問題總結

[b]1. 由使用併發看到的[/b]
在處理大數據量任務時,可以做到的要麼提高執行效率,要麼併發執行。如果在單線程效率達到瓶頸時,不得不引入併發,並面對隨之而來的問題。在我的程序中,多線程刪除某個目錄下的所有文件,或是多線程往同一文件中寫數據,都得考慮同步時的爭鎖問題。
[list]
[*]線程數量有閾值,並不是越多越好。因應用而定,對共享的爭用是需要權衡的。
[*] 設置條件,減少多線程進入同步塊的機會。如每條線程執行500條數據,纔去檢查共享目錄的文件。
[*]在頻繁出現資源爭用的情況時,爲不同線程設置不同的sleep時間,錯開執行。[/list]

[b]2. 持續優化可以確定的性能瓶頸[/b]
[color=darkred]優化絕對是建立在對已有程序執行效率的分析結果上[/color]。在我的程序中經歷的優化有:在單線程性能已無法提高時,選擇多線程 --> 解決線程爭用共享資源 --> 排除很多無效數據也要下載文件且佔據網絡資源的情況 --> 解決部分數據依賴於第三方jar包,長時間沒有數據返回的問題等。優化之前在可能出現性能問題的地方設置時間點,分析執行時間,以執行時間爲依據做代碼review。

[b]3. 讓程序更聰明些[/b]
在程序運行期,我們希望得到它的執行進度、效率、指出程序瓶頸在哪,更期望程序從主動從問題中恢復,這些要求在程序開發階段不會考慮太全,需要經過實踐的驗證,並不斷補充。這個問題以前就認識到,但要寫出些能上得了檯面的東西,還是需要不斷積累。
[list]
[*]在網絡超時,系統負載高的時候能減緩執行,反之加快執行速度。
[*]如果某些資源在使用一段時間後頻繁出現訪問延時,就每隔一段時間重啓執行程序。
[*]分析每個線程的執行效率,或分析線程數量的較優解
[*]... ...
[/list]
[b]4. 對BufferedWriter的併發訪問[/b]
程序中多線程往同一文件中寫數據,使用BufferedWriter。之前沒有看過BufferedWriter的代碼,在訪問BufferedWriter之前做同步處理,並在每次append()之後都做flush()操作,造成程序性能損耗嚴重。在同事的提醒下,修正爲每個線程執行N次後再做flush。
看了下BufferedWriter的代碼,對上面的兩個問題的解釋:
1. [color=blue]多線程訪問BufferedWriter是否需要同步[/color]
BufferedWriter自帶鎖,同步對流的訪問,所以在外面的同步可要可不要。(append同write方法)[/size]

protected Object lock;
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
}


[size=medium]2. [color=blue]如果append後不做flush,誰來flush[/color]
BufferedWriter自設緩存,且默認大小爲8K,大小可修改。[/size]

private char cb[];
private static int defaultCharBufferSize = 8192;

public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
}

[size=medium]在往BufferedWriter寫數據時,當它發現緩存已滿,就將緩存數據寫入流中,將新到的數據再次放入緩存中。也就是說如果程序不主動flush的話,當數據值積累到默認緩存大小時,BufferedWriter會自動將緩存數據flush入writer流中。
還有,當BufferedWriter關閉的時候,也會把所有緩存數據自動flush.[/size]

public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try {
flushBuffer();
} finally {
out.close();
out = null;
cb = null;
}
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章