2013-08-25 44 views
6

我看Roslyn September 2012 CTP與反射,我注意到SlidingTextWindow類有以下幾點:爲什麼在這種情況下使用ConcurrentQueue?

internal sealed class SlidingTextWindow : IDisposable 
{ 
    private static readonly ConcurrentQueue<char[]> arrayPool = new ConcurrentQueue<char[]>(); 
    private int basis; 
    private readonly LexerBaseCache cache; 
    private char[] characterWindow; 
    private int characterWindowCount; 
    private int characterWindowStart; 
    private int offset; 
    private readonly IText text; 
    private readonly int textEnd; 

    public SlidingTextWindow(IText text, LexerBaseCache cache) 
    { 
     this.text = text; 
     this.basis = 0; 
     this.characterWindowStart = 0; 
     this.offset = 0; 
     this.textEnd = text.Length; 
     this.cache = cache; 
     if (!arrayPool.TryDequeue(out this.characterWindow)) 
     { 
      this.characterWindow = new char[2048]; 
     } 
    } 

    public void Dispose() 
    { 
     arrayPool.Enqueue(this.characterWindow); 
     this.characterWindow = null; 
    } 

    // ... 
} 

我相信這個類的目的是提供輸入文本的子快速訪問,通過使用char[] characterWindow,一次從2048個字符開始(儘管characterWindow可能增長)。我相信這是因爲字符數組的子字符串比字符串更快,正如Eric Lippert seems to indicate on his blog

每次Lexer類實例化時,SlidingTextWindow類都會實例化,每次調用SyntaxTree.ParseText時都會發生這種類。

我不明白arrayPool字段的用途。它在這個類中的唯一用法是在構造函數和Dispose方法中。當致電SyntaxTree.ParseText時,似乎只創建了Lexer類和SlidingTextWindow類的一個實例。當一個實例處理時排隊characterWindow,並且在創建一個實例時嘗試將一個characterWindow排隊,會帶來什麼好處?

也許有人來自羅斯林團隊可以幫助我理解這一點?

回答

16

優點是收集壓力降低,對整體性能有積極影響。

.NET垃圾回收器當然是一個通用垃圾回收器。編譯器和IDE的分配和對象生命週期模式與您的平均業務線應用程序的分配和對象生命週期模式完全不同,它們往往以不同尋常的方式強調GC。

如果你看看整個羅斯林,有很多地方小型數組被緩存並在以後重新使用,而不是讓GC將它們識別爲短期垃圾並立即回收它們。經驗性實驗表明,這在性能上有了可衡量的改進。

我不建議在您自己的應用程序中這樣做,除非您的分析表明您的收集壓力有可衡量的性能問題。對於絕大多數應用程序來說,GC已經很好地進行了調整,並且共享策略的好處不值得相當可觀的成本。

+0

是否爲減少內存或提高速度(或兩者)的主要目的完成小陣列的緩存?是否有如此多的編譯器/ IDE所必需的數組,每次創建一個新數組都會佔用大量內存?或者是否會通過使用線程安全隊列並使多個線程作用於陣列來提高速度? – cubetwo1729

+11

主要是速度和響應速度。 GC在性能方面很有意思 - 它幾乎可以免費分配內存,但當GC運行時,您需要付出代價。在某些情況下,如果在編寫代碼的同時在編輯器中鍵入字符時發生運行,則GC對鍵入有明顯的影響,並且無法執行完全併發的GC。 我確實想強調Eric所說的 - 我們只在我們看到配置文件中出現特定分配時才這樣做。除非我們知道這是特定位置的特定問題,否則我們不會這樣做。 –

+0

@JasonMalinowski挑選'ConcurrentQueue'而不是'ConcurrentBag'的任何特定原因? – CodesInChaos

相關問題