2011-12-07 149 views
1

我可能需要對大代碼庫和不同工具進行多次讀取。 然後我認爲在文本不會改變的情況下在磁盤上讀取這麼多次真是太浪費了,所以我寫了以下內容。緩存磁盤操作

class Module(object): 
    def __init__(self, module_path): 
     self.module_path = module_path 
     self._text = None 
     self._ast = None 

    @property 
    def text(self): 
     if not self._text: 
      self._text = open(self.module_path).read() 
     return self._text 

    @property 
    def ast(self): 
     s = self.text # which is actually discarded 
     if not self._ast: 
      self._ast = parse(self.text) 

     return self._ast 


class ContentDirectory(object): 
    def __init__(self): 
     self.content = {} 

    def __getitem__(self, module_path): 
     if module_path not in self.content: 
      self.content[module_path] = Module(module_path) 

     return self.content[module_path] 

但現在問題出現了,因爲我想避免更改其餘代碼,同時能夠使用這種新技巧。例如,我看到的唯一方法就是在任何可能使用的地方修補「open」內置函數。

from myotherlib import __builtins__ as other_builtins 
other_builtins.open = my_dummy_open # which uses this cache 

但它似乎並不是一個明智的想法。 我應該放棄,只有在表演真的太糟糕時才試試?

+3

「我是不是應該放棄,如果表現實在太糟糕也許只有試試?」 - 幾乎肯定是的。 OS級別將爲您處理緩存文件。如果你可以做得更好(例如,你比使用OS更好地理解訪問模式),那麼只需要緩存,但是如果你真的需要首先完成,總是值得一看。 –

+0

'parse()'實際需要多少時間?多少次它可以節省重新解析?你的程序/計算機可以用'_ast'實際佔用但未被使用的內存做些更有用的事情嗎? – sarnold

+0

操作系統無法做到奇蹟,而且從我的小測試中,緩存和非緩存版本之間的時間差別很大,特別是如果我分析了大量文件。 –

回答

1

我不確定此庫提供的功能是否適用於您的場景,但是想到提及linecache library的存在。從鏈接的文檔:

linecache模塊允許從任何文件中獲取任何行,同時嘗試使用緩存進行內部優化,這是一種常見的情況,即從單個文件中讀取多行。

...這當然不來,甚至接近你實現在一個優雅的和透明的方式解決問題...

2

更換系統open()調用可能是一個壞事。它要求所有使用open()的東西都按照你的期望使用它。

爲什麼要避免更改代碼?

是的,測量性能,看看它是否值得。例如,放入上面的代碼,看看有多快。如果它只有1%的速度,那麼沒有理由做任何事情。如果速度更快,那麼請查看open()的使用情況,如果可以的話更改該代碼。

順便說一句,類似於LRU cache(Python 3.2中的functools的一部分)也會對您的任務有所幫助。