2013-08-25 1 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처럼 문자열보다 문자 배열의 부분 문자열을 취하는 것이 더 빠르기 때문입니다.

SlidingTextWindow 클래스는 Lexer 클래스가 인스턴스화 될 때마다 인스턴스화되며, SyntaxTree.ParseText을 호출 할 때마다 발생합니다.

arrayPool 필드의 목적을 이해할 수 없습니다. 이 클래스의 유일한 용도는 생성자 및 Dispose 메서드입니다. SyntaxTree.ParseText을 호출하면 Lexer 클래스와 SlidingTextWindow 클래스의 인스턴스가 하나만 생성 된 것으로 보입니다. 인스턴스가 삭제 될 때 을 대기열에 추가하고 인스턴스가 생성 될 때 characterWindow을 대기열에서 제외하려고하면 어떤 이점이 있습니까?

아마도 Roslyn 팀의 누군가가 이것을 이해하는 데 도움이 될까요?

답변

16

장점은 수집 압력이 감소되어 전체 성능에 긍정적 인 영향을 미친다는 것입니다.

.NET 가비지 수집기는 물론 범용 가비지 수집기입니다. 컴파일러와 IDE의 할당 및 개체 수명 패턴은 일반적인 LOB (기간 업무) 응용 프로그램의 패턴과 상당히 다르며 비정상적인 방식으로 GC를 강조하는 경향이 있습니다.

Roslyn을 살펴보면 작은 배열이 캐싱되어 나중에 GC가 단명 쓰레기로 식별하여 즉시 회수하도록 허용하는 대신 많은 장소가 있습니다. 경험적 실험에 따르면 성능에서 상당한 향상을 볼 수 있습니다.

프로파일 링에서 수집 압력에 대한 측정 가능한 성능 문제가 있음을 나타내지 않는 한 자신의 응용 프로그램에서 그렇게하는 것을 권장하지 않습니다. 대다수의 애플리케이션에서 GC는 매우 잘 조정되어 있으며 풀링 전략의 이점은 상당한 비용이 들지 않습니다.

+0

작은 배열의 캐싱은 메모리를 줄이거 나 속도를 높이는 것이 주 목적입니까? 컴파일러/IDE에 필요한 많은 배열이 있기 때문에 매번 새로운 배열을 만들면 많은 메모리가 필요합니까? 또는 스레드 안전 큐를 사용하고 배열에 여러 스레드가 작동하여 속도가 향상됩니까? – cubetwo1729

+11

주로 속도와 응답 성. GC는 성능 측면에서 흥미 롭습니다. 메모리를 거의 무료로 할당 할 수 있지만 나중에 GC를 실행해야 할 때 비용을 지불하게됩니다. 그리고 어떤 경우에는 코드를 작성하는 동안 문자를 편집기에 입력하는 것처럼 실행되는 경우 GC가 완전히 동시 GC를 수행 할 수없는 경우 입력에 눈에 띄는 영향을줍니다. 에릭이 언급 한 것을 강조하고 싶습니다. 특정 할당이 프로필에 표시되는 것을 볼 때만 이것을 수행합니다. 특정 위치에서 특정 문제가 발생할 때까지는 이런 일을하지 않습니다. –

+0

@JasonMalinowski 'ConcurrentBag'대신 'ConcurrentQueue'를 선택해야하는 구체적인 이유는 무엇입니까? – CodesInChaos