4/28/2007

Rails Cache 效率上的問題

Fragement Cache 是大家常用的Rails 內建 Cache 機制,不過昨天看到石鍋拌飯先生寫的rails缓存机制的几个问题,裡面提到一些 Fragement Cache 的問題,這裡做一下筆記。




1. read_fragment 實做方式效率不佳

actionpack/lib/action_controller/caching.rb 裡面,read_fragment 假設是使用 file_store 的話,實做方式不佳
def read(name, options = nil) #:nodoc:
File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil
end
每次判斷 fragment 都得 open file 一次,的確會損耗效率。解決方式是用 File.exist? 來判斷即可。

2. expire_fragment 使用 regular expression 效率不佳

不算問題啦,假設 expire_fragment 使用 regular expression ,根據內建的實做方式,他會一個一個目錄下去用 regular expression ,然後 regular expression 通常執行速度不佳,所以就....

解決方式有兩個,第一個就是不要在 expire_fragment 使用 regular expression,另外就是使用 backend script 來 expire cache 即可。

3. expire_cache 的時間點

簡單講就是 controller read_fragment 的到 cache ,但是當 render 的時候卻剛剛好被 expire 掉了,就會出現 nil object error 。因為發生機率比較低,解決方式只能說視情況而定。

當然也可以照著原作者的講法,在 view 當中判斷 Model obj 是不是存在,不過這個作法就比較 dirty。

4 則留言:

Lovely Day 提到...

我的做法是, 在 controller 裡建一個 late finder (也有人叫 lazy data fetcher), 把實際從Database讀資料的工作延後到 rendering view 時才做, 這樣就不需要在 controller 裡判斷 cache 是否存在, 也不需要擔心石鍋拌飯先生提到的問題.

舉一個簡單的例子:

class MyController
def index
@articles = LateArticleFinder(params[:tags])
end
end

class LateArticleFinder
def initialize(tags)
@tags = tags
end
def load
Article.find_by_tags(tags)
end
end

在 index.rhtml 裡用 @articles.load 取資料

thegiive 提到...

你的說法的確是一個辦法,不過這樣似乎有點不合乎 MVC 的規範 :p
不過 cache 本來就是特殊解法,好像也沒有一定要按照啥規則

Lovely Day 提到...

從執行流程來看, 這個做法的確不是標準的 MVC, 但是從實作面來看, 我們把 late fetcher 放在 controller 同一個檔案裡, 可以和 controller 同時維護, 完全依循 MVC 的精神, 並不相悖.

thegiive 提到...

您說的沒錯,不是我說你錯,不過我對這樣的作法略嫌麻煩了點 :p 而且也不符合本人毫無意義的美學,所以敬謝不敏

當然,code work 即可,Ruby 裡面鼓勵每個人寫不一樣的 code (Python 即反之)