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í.
Doporučená akce
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 EventListener
hodnoty čí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 EventListener
ně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++
.