为什么在这种情况下使用ConcurrentQueue?

时间:2013-08-25 14:19:12

标签: c# roslyn

我正在使用Reflector查看Roslyn September 2012 CTP,我注意到SlidingTextWindow类具有以下内容:

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

每次实例化SlidingTextWindow类时都会实例化Lexer类,每次调用SyntaxTree.ParseText时都会发生这种情况。

我不明白arrayPool字段的用途。它在此类中的唯一用法是在构造函数和Dispose方法中。调用SyntaxTree.ParseText时,似乎只创建了Lexer类和SlidingTextWindow类的一个实例。通过在放置实例时将characterWindow排入队列并在创建实例时尝试使characterWindow出列,可以获得什么好处?

也许Roslyn团队的某位成员可以帮助我理解这一点?

1 个答案:

答案 0 :(得分:17)

优点是收集压力降低,这对整体性能有积极影响。

.NET垃圾收集器当然是一个通用的垃圾收集器。编译器和IDE的分配和对象生存期模式与平均业务线应用程序的模式完全不同,并且它们倾向于以不寻常的方式强调GC。

如果您在整个Roslyn中查看,有许多地方会缓存小型数组并在以后重新使用,而不是让GC将它们识别为短期垃圾并立即回收它们。经验实验表明,这可以带来可衡量的绩效改善。

我不建议您在自己的应用程序中这样做,除非您的分析表明您在收集压力上存在可衡量的性能问题。对于绝大多数应用程序而言,GC的调整非常好,并且汇集策略的好处不值得花费相当大的成本。