다음을 통해 공유


IncrementingPollingCounter 초기 콜백은 비동기적임

IncrementingPollingCounter는 콜백을 사용하여 메트릭의 현재 값을 검색하고 EventSource 이벤트를 통해 보고합니다. 과거에는 콜백의 첫 번째 호출이 EventSource를 사용하도록 설정하는 어떤 스레드에서든 동기적으로 발생했을 수 있지만, 이후 호출은 전용 타이머 스레드에서 발생했습니다. .NET 9부터 첫 번째 콜백은 항상 타이머 스레드에서 비동기적으로 발생합니다. 이로 인해 첫 번째 콜백이 나중에 발생하므로 카운터를 사용하도록 설정한 직후 발생한 카운터의 변화가 관찰되지 않을 수 있습니다.

이 변경 내용은 EventListener를 사용하여 IncrementingPollingCounter의 유효성을 검사하는 테스트에 영향을 미칠 가능성이 가장 높습니다. 테스트에서 카운터를 사용하도록 설정한 다음, 카운터에서 폴링되는 상태를 즉시 수정하는 경우, 콜백이 처음 호출되기 전에 해당 수정이 발생할 수 있습니다(눈에 띄지 않음).

이전 동작

이전에는 IncrementingPollingCounter를 사용하도록 설정한 경우 콜백의 첫 번째 호출이 사용 설정 작업을 수행한 스레드에서 동기적으로 발생했을 수 있습니다.

이 샘플 앱은 () => SomeInterestingValue 호출 내의 Main 스레드에서 대리자 EnableEvents()를 호출합니다. 이 콜백은 log.SomeInterestingValue가 0임을 관찰합니다. 나중에 전용 타이머 스레드의 호출은 log.SomeInterestingValue가 1로 변경된 것을 관찰하고 Increment value = 1과 함께 이벤트를 보냅니다.

using System.Diagnostics.Tracing;

var log = MyEventSource.Log;
using var listener = new Listener();

log.SomeInterestingValue++;

Console.ReadKey();

class MyEventSource : EventSource
{
    public static MyEventSource Log { get; } = new();
    private IncrementingPollingCounter? _counter;
    public int SomeInterestingValue;

    private MyEventSource() : base(nameof(MyEventSource))
    {
        _counter = new IncrementingPollingCounter("counter", this, () => SomeInterestingValue);
    }
}

class Listener : EventListener
{
    protected override void OnEventSourceCreated(EventSource eventSource)
    {
        if (eventSource.Name == nameof(MyEventSource))
        {
            EnableEvents(eventSource, EventLevel.Informational, EventKeywords.None,
                new Dictionary<string, string?> { { "EventCounterIntervalSec", "1.0" } });
        }
    }

    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        if (eventData.EventSource.Name == "EventCounters")
        {
            var counters = (IDictionary<string, object>)eventData.Payload![0]!;
            Console.WriteLine($"Increment: {counters["Increment"]}");
        }
    }
}

새 동작

이전 동작 섹션과 동일한 코드 조각을 사용하여 타이머 스레드에서 콜백의 첫 번째 호출이 비동기적으로 발생합니다. OS가 여러 스레드를 예약하는 방식에 따라 Main 스레드가 log.SomeInterestingValue++를 실행하기 전에 발생할 수도 있고 그렇지 않을 수도 있습니다.

이 타이밍에 따라 앱은 "Increment=0" 또는 "Increment=1"을 출력합니다.

도입된 버전

.NET 9 RC 1

호환성이 손상되는 변경의 형식

이 변경 사항은 동작 변경입니다.

변경 이유

EventListener 잠금이 유지되는 동안 콜백 함수를 실행하여 발생할 수 있는 잠재적 교착 상태를 해결하기 위해 변경되었습니다.

외부 모니터링 도구에서 메트릭을 시각화하는 데 IncrementingPollingCounters를 사용하는 시나리오에는 아무런 조치도 필요하지 않습니다. 이러한 시나리오는 정상적으로 계속 작동해야 합니다.

EventListener를 통해 프로세스 내 테스트 또는 기타 카운터 데이터를 사용하는 시나리오의 경우, 코드에서 EnableEvents()를 호출한 동일한 스레드에서 만든 카운터 값의 특정 수정 사항을 관찰해야 하는지 확인합니다. 그렇다면 EventListener에서 하나 이상의 카운터 이벤트를 관찰할 때까지 대기한 다음, 카운터 값을 수정하는 것이 좋습니다. 예를 들어 예제 코드 조각이 "Increment=1"을 인쇄하도록 하려면 ManualResetEventEventListener에 추가하고, 첫 번째 카운터 이벤트가 수신되면 신호를 보낸 다음, log.SomeInterestingValue++를 호출하기 전에 대기할 수 있습니다.

영향을 받는 API