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

本文关键字:ConcurrentQueue 这种情况下 为什么 | 更新日期: 2023-09-27 18:29:01

我正在查看带有Reflector的Roslyn 2012年9月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在他的博客上指出的那样,从字符数组中提取子字符串比从字符串中提取子串更快。

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

我不理解arrayPool字段的用途。它在此类中的唯一用法是在构造函数和Dispose方法中。调用SyntaxTree.ParseText时,似乎只创建了Lexer类和SlidingTextWindow类的一个实例。当处理实例时将characterWindow排队,而当创建实例时尝试将characterWindow出列,这有什么好处?

也许罗斯林团队的某个人可以帮我理解这一点?

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

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

.NET垃圾收集器当然是一个通用的垃圾收集器。编译器和IDE的分配和对象生存期模式与普通业务线应用程序的分配和目标生存期模式大不相同,而且它们往往以不同寻常的方式强调GC。

如果您查看整个Roslyn,有许多地方的小数组被缓存并在以后重新使用,而不是让GC将它们识别为短暂的垃圾并立即回收。经验实验表明,这在性能上有了可衡量的改进。

我不建议在您自己的应用程序中这样做,除非您的评测表明您在收集压力下存在可测量的性能问题。对于绝大多数应用程序,GC都经过了很好的调整,池策略的好处不值得付出巨大的成本。