Sdílet prostřednictvím


Počáteční zpětné volání IncrementingPollingCounter je asynchronní

IncrementingPollingCounter pomocí zpětného volání načte aktuální hodnoty metriky a hlásí ji prostřednictvím EventSource událostí. V minulosti mohlo dojít k prvnímu vyvolání zpětného volání synchronně v jakémkoli vlákně, které povolilo EventSource; budoucí vyvolání proběhlo ve vyhrazeném vlákně časovače. Počínaje rozhraním .NET 9 se první zpětné volání vždy provádí asynchronně ve vlákně časovače. To může vést ke změnám čítačů, ke kterým došlo hned po povolení čítače, protože první zpětné volání proběhne později.

Tato změna pravděpodobně ovlivní testy, které používají EventListener k ověření IncrementingPollingCounter. Pokud testy povolí čítač a okamžitě upraví stav dotazovaný čítačem, může k této úpravě dojít před prvním vyvoláním zpětného volání (a bez upozornění).

Předchozí chování

Dříve, když IncrementingPollingCounter byl povolen, první vyvolání zpětného volání mohlo dojít synchronně ve vlákně, které provedlo operaci povolení.

Tato ukázková aplikace volá delegáta () => SomeInterestingValue ve vlákně Main v rámci volání .EnableEvents() Toto zpětné volání bude sledovat log.SomeInterestingValue 0. Pozdější volání z vyhrazeného vlákna časovače bude sledovat log.SomeInterestingValue změny na 1 a událost bude odeslána s 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"]}");
        }
    }
}

Nové chování

Při použití stejného fragmentu kódu jako v předchozí části chování dochází k prvnímu vyvolání zpětného volání asynchronně ve vlákně časovače. Může nebo nemusí nastat před spuštěním Main log.SomeInterestingValue++ vlákna v závislosti na tom, jak operační systém plánuje více vláken.

V závislosti na daném načasování aplikace buď vypíše "Increment=0" nebo "Increment=1".

Zavedená verze

.NET 9 RC 1

Typ zásadní změny

Tato změna je změna chování.

Důvod změny

Změna byla provedena, aby se vyřešil potenciální vzájemné zablokování, ke kterému může dojít při zamknutí funkcí zpětného EventListener volání.

Pro scénáře, které se používají IncrementingPollingCounters k vizualizaci metrik v externích monitorovacích nástrojích, není nutná žádná akce. Tyto scénáře by měly dál normálně fungovat.

V případě scénářů, které provádějí testování v procesu nebo jiné využití dat čítačů prostřednictvím EventListener, zkontrolujte, jestli váš kód očekává, že bude sledovat konkrétní úpravy hodnoty čítače provedené ve stejném vlákně, které volal EnableEvents(). Pokud ano, doporučujeme počkat na sledování alespoň jedné události čítače z EventListenerhodnoty čítače a pak upravit hodnotu čítače. Pokud chcete například zajistit, aby ukázkový fragment kódu vytiskl text "Increment=1", můžete do EventListenerněj přidat ManualResetEvent znak , signalizovat ho při přijetí první události čítače a počkat na to, než zavoláte log.SomeInterestingValue++.

Ovlivněná rozhraní API