2013-08-25 46 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

相关问题