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.
Aanbevolen actie
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 EventListener
teller, 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 EventListener
codefragment toevoegen, een signaal geven wanneer de eerste tellergebeurtenis wordt ontvangen en wachten totdat u het aanroeptlog.SomeInterestingValue++
.