sto guardando la Roslyn September 2012 CTP con riflettore, e ho notato che la classe SlidingTextWindow ha la seguente:Perché utilizzare ConcurrentQueue in questo caso?
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;
}
// ...
}
Credo che lo scopo di questa classe è quello di fornire un rapido accesso alle sottostringhe del testo di input, utilizzando char[] characterWindow
, che inizia con 2048 caratteri alla volta (sebbene lo characterWindow
potrebbe aumentare). Credo che sia perché è più veloce prendere sottostringhe di matrici di caratteri che di archi, come Eric Lippert seems to indicate on his blog.
La classe SlidingTextWindow
viene istanziata ogni volta che la classe Lexer
viene creata un'istanza, il che avviene ogni chiamata a SyntaxTree.ParseText
.
Non capisco lo scopo del campo arrayPool
. Il suo unico utilizzo in questa classe è nei metodi costruttore e Dispose. Quando si chiama SyntaxTree.ParseText
, sembra esserci solo un'istanza della classe Lexer
e della classe SlidingTextWindow
creata. Quale vantaggio si ottiene accodando lo characterWindow
quando un'istanza viene eliminata e tentando di annullare la riacquisizione di uno characterWindow
quando viene creata un'istanza?
Forse qualcuno del team di Roslyn potrebbe aiutarmi a capirlo?
La memorizzazione nella cache di matrici di piccole dimensioni viene eseguita per lo scopo principale di ridurre la memoria o aumentare la velocità (o entrambi)? È il caso che con così tanti array necessari per un compilatore/IDE, la creazione di un nuovo array ogni volta occupi molta memoria? O ci sarebbe un aumento di velocità usando una coda thread-safe e avendo più thread agire sugli array? – cubetwo1729
Principalmente velocità e reattività. Il GC è interessante quando si tratta di prestazioni: consente di allocare memoria quasi gratuitamente, ma si paga il costo più tardi quando il GC deve essere eseguito. E in alcuni casi, il GC ha un impatto notevole sulla digitazione, se dovesse accadere mentre si digita un carattere nell'editor durante la scrittura del codice e non è stato possibile eseguire un GC completamente concorrente. Desidero mettere in risalto ciò che ha menzionato Eric - lo facciamo solo quando vediamo che una determinata allocazione si presenta nei profili. Non facciamo cose del genere finché non sappiamo che si tratta di un problema specifico in un luogo specifico. –
@JasonMalinowski Qualche motivo specifico per scegliere 'ConcurrentQueue' invece di' ConcurrentBag'? – CodesInChaos