Delen via


IncrementingPollingCounter initiële callback is asynchroon

IncrementingPollingCounter gebruikt een callback om de huidige waarden van een metrische waarde op te halen en rapporteert deze via EventSource gebeurtenissen. In het verleden is de eerste aanroep van de callback synchroon opgetreden op de thread die de EventSource; toekomstige aanroepen plaatsvonden op een toegewezen timerthread. Vanaf .NET 9 vindt de eerste callback altijd asynchroon plaats op de timerthread. Dit kan leiden tot wijzigingen in tellers die zijn opgetreden vlak nadat de teller niet-zichtbaar was, omdat de eerste callback later plaatsvindt.

Deze wijziging is waarschijnlijk van invloed op tests die worden gebruikt EventListener om een IncrementingPollingCounter. Als tests de teller inschakelen en vervolgens onmiddellijk de status wijzigen die door de teller wordt gepeild, kan die wijziging nu plaatsvinden voordat de callback voor het eerst wordt aangeroepen (en onopgemerkt blijven).

Vorig gedrag

Voorheen, toen een IncrementingPollingCounter functie was ingeschakeld, is de eerste aanroep van de callback mogelijk synchroon opgetreden in de thread die de inschakelbewerking heeft uitgevoerd.

Deze voorbeeld-app roept de gemachtigde () => SomeInterestingValue aan op de Main thread binnen de aanroep naar EnableEvents(). Die callback zal zien log.SomeInterestingValue is 0. Een latere aanroep van een speciale timerthread ziet dat log.SomeInterestingValue deze is gewijzigd in 1 en er wordt een gebeurtenis verzonden met 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"]}");
        }
    }
}

Nieuw gedrag

Met behulp van hetzelfde codefragment als de sectie Vorige gedrag , vindt de eerste aanroep van de callback asynchroon plaats op de timerthread. Dit kan al dan niet gebeuren voordat de Main thread wordt uitgevoerd log.SomeInterestingValue++ , afhankelijk van hoe het besturingssysteem meerdere threads plant.

Afhankelijk van deze timing voert de app 'Increment=0' of 'Increment=1' uit.

Versie geïntroduceerd

.NET 9 RC 1

Type wijziging die fouten veroorzaken

Deze wijziging is een gedragswijziging.

Reden voor wijziging

De wijziging is aangebracht om een mogelijke impasse op te lossen die kan optreden bij het uitvoeren van callback-functies terwijl de EventListener vergrendeling wordt vastgehouden.

Er is geen actie vereist voor scenario's die gebruikmaken IncrementingPollingCounters van het visualiseren van metrische gegevens in externe bewakingshulpprogramma's. Deze scenario's moeten normaal blijven werken.

Voor scenario's die in-process testen of ander verbruik van tellergegevens uitvoeren via EventListener, controleert u of uw code verwacht een specifieke wijziging van de tellerwaarde te observeren die is gemaakt op dezelfde thread die werd aangeroepen EnableEvents(). Als dit het geval is, raden we u aan om te wachten op ten minste één teller-gebeurtenis van de EventListenerteller, en vervolgens de tellerwaarde te wijzigen. Als u er bijvoorbeeld voor wilt zorgen dat in het voorbeeldcodefragment 'Increment=1' wordt afgedrukt, kunt u een aan ManualResetEvent het EventListenercodefragment toevoegen, een signaal geven wanneer de eerste tellergebeurtenis wordt ontvangen en wachten totdat u het aanroeptlog.SomeInterestingValue++.

Betrokken API's