免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 867 | 回复: 0
打印 上一主题 下一主题

探索產生物件的技巧(7)避免時效性不高的重複性動作 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-08 18:32 |只看该作者 |倒序浏览

一個點擊網站首頁的動作,可能引發資料庫執行多筆的查詢。事實上,資訊的變化並不一定很快速,重新查詢的代價卻十分沈重。因此,我們需要物件快取,節省耗費成本的動作。
不論是泛Factory族系的設計模式、Singleton,或者Object Pool,都是透過一個間接的角色或機制,封裝產生或取得物件的過程。應用泛Factory族系設計模式時,每次都重新產生新的物件,但運用Singleton及Object Pool時則不然。
運用Singleton,從頭到尾頂多只產生一份物件實體,而運用Object Pool時,雖然有可能產生多份實體,但是使用自Object Pool中取出的物件時,不一定會取出全新製品,也有可能拿到回收再製品。這意謂著用戶端在使用物件時,並不在乎所拿到的物件,究竟是不是剛產生的。只要能滿足需求,就算是二手貨,沒有什麼分別。
快取的時機──反覆高成本的虛工
就跟現實世界的資源回收再利用一樣,回收使用過的物件,避免重新製造物件,是為了節省成本。我們可以應用Object Pool管理那些產生或清理的成本高昂、同時可重複使用的物件。
接下來,我要介紹另一種物件回收再利用的機制-物件快取(Object Caching)。
「快取(Caching)」是開發者耳熟能詳的名詞。在電腦的領域裡,「快取」一詞無所不在,好比CPU快取、磁碟快取、瀏覽器端的檔案快取等。而在軟體開發領域,快取的概念也是時常被用來提高執行效率的方式。
舉個例子,使用資料庫存取資料的應用程式,為了產生結果呈現給使用者查詢。對企業入口網站(Enterprise Information Portal)而言,當使用者點擊首頁時,就必須從資料庫查詢最新或熱門的公告、商情資訊、知識管理中心裡的知識、企業內部論壇中的討論等。
可以想見,即便是一個點擊網站首頁的簡單動作,就可能引發系統向資料庫執行多筆的查詢。當網站同時使用的人數增加時,系統連結至資料庫查詢的負擔就會增加。
但是,這些資訊的變化通常並不快速,也就是說,雖然系統每次都重新向資料庫查詢最新的資料,但幾乎都得到一模一樣的結果,因為資料根本沒有更新。然而,重新查詢的代價卻可能十分沈重,結果像是白做工。
開發者有可能利用類似以下的程式碼查詢資料庫的資料:
DataSet ds = databaseAccessor.sqlQuery
(“select * from HotNews”);
databaseAccessor 是提供SQL查詢功能的物件,接收SQL述句做為引數,並且回傳DataSet用以表示查詢所得的資料。我們不難想像,sqlQuery()的實作,便是建立(或自Database Connection Pool中取得)資料庫連線物件,然後執行SQL查詢,再產生一個DataSet物件,將查詢所得的結果置於其中。
這麼一來,產生一個代表我們所需資料的物件-DataSet,就成了成本高昂的動作。對於某些應用情境來說,有可取捨之處:捨棄資料更新的即時性以換取系統運行的效能。
透過物件快取,反覆運用特定狀態的物件
我們應該使用Object Pool,避免重複產生DataSet的代價嗎?當然不,使用自Object Pool中取出的物件前,該物件會被設置在某個初始(像是全新未使用)的狀態,但這並不是我們想要的。
我們希望產生物件後,能夠繼續維持狀態一陣子,直到有效狀態過期為止,而在物件所持有的狀態有效期內,反覆運用這個物件,而不需一次又一次耗費昂貴的代價,重新取得該物件所代表的狀態。
這個時候,我們需要的是──物件快取。
就以上述的DataSet為例,為它設計一個SQLDataSetCache,提供快取的機制:
public class SQLDataSetCache
{
     public DataSet sqlQueryCached
(String sql, int refreshInterval);
     public void invalidateSQLQueryCached
(String sql);
}
其中最主要的Method就是sqlQueryCached()。當用戶端需要表示某一SQL查詢述句結果的DataSet物件時,便直接呼叫SQLDataSetCache,然後讓SQLDataSetCache封裝其中的所有邏輯。
當sqlQueryCached()被呼叫時,會傳入兩個引數,分別是欲查詢的SQL述句(sql)以及資料有效期(refreshInterval)。SQLDataSetCache內部維護一份對照表(若以Java實作,可能採取HashMap,若以.NET實作便是Hashtable),以SQL述句為Key, SQL述句查詢後的DataSet為值,給定一條SQL述句,便能對應到該SQL述句的查詢結果。
在sqlQueryCached()的實作裡,倘若傳入的sql引數找不到相對應的DataSet,這表示快取中並不存在任何資料,此時,便實際透過資料庫連線執行查詢,取得查詢結果,然後據以建立DataSet物件。
在建立DataSet物件後,SQLDataSetCache可以記錄產生的時間,並且將DataSet物件以sql引數為Key置入對照表中,以便日後的取用。
在sqlQueryCached()的實作裡,倘若傳入的sql引數能找到相對應的DataSet,此時便能進一步檢查該DataSet的建立時間,倘若此刻還在refreshInterval所設定的有效期間之內,代表快取中的DataSet尚可用,便可直接回傳快取中的DataSet物件。倘若已經過了有效期,便需要重新查詢資料庫,建立一份全新的DataSet,置入快取之中。
明確知道快取失效時,乾脆主動移除物件
在上述的應用中,我們利用refreshInterval控制快取內物件更新的時機。不過,在某些情況下,我們可以很明確知道快取內的物件已經失效。例如,對表示企業最新公告的DataSet物件而言,當使用者透過系統新增一筆新的企業最新公告訊息時,系統很明確知道最新公告有所更動,此時不需要等到快取物件過期,便可以立即更新資料。
在這種情況下,系統便可以使用invalidateSQLQueryCached(),要求SQLDataSetCache將指定SQL述句所對應的DataSet物件自快取中移除,待下回sqlQueryCached()被呼叫時,便因為快取中已無DataSet,而重新查詢資料庫,取得最新的資料。
物件快取可說是效能調校的捷徑
除了上述所提的資料庫查詢物件快取之外,物件快取更常被廣泛運用在調整系統效能,它幾乎是條快速的捷徑。當你發現系統中出現效能瓶頸,而這個瓶頸是導因於反覆為了取得某些資訊而做了耗損時間的動作,只要這些資訊的變化不頻繁,而且不講究即時性,就很適合利用物件快取提升效能。
Object Pool和Object Cache都是回收再利用物件的機制。不同的是,在運用Object Pool時,會預期每次從Object Pool中取出的物件,都像是全新未使用的,而在運用Object Cache時,我們的目的反而是希望重複使用Object Cache中已具狀態的物件,這是二者最大的差異。
《作者簡介》王建興
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/32667/showart_396863.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP