共用方式為


IncrementingPollingCounter 初始回呼為非同步

IncrementingPollingCounter 使用回呼來擷取計量的目前值,並透過 EventSource 事件報告。 在過去,回呼的第一個叫用可能會在啟用 EventSource 的任何執行緒上同步發生;未來叫用發生在專用計時器執行緒。 從 .NET 9 開始,第一個回呼一律會在計時器執行緒上以非同步方式發生。 這可能會導致計數器變更在計數器啟用之後發生,因為第一次回呼發生的時間較晚。

此變更最有可能影響使用 EventListener 來驗證 IncrementingPollingCounter 的測試。 如果測試啟用計數器,然後立即修改計數器正在輪詢的狀態,該修改現在可能會在第一次叫用回呼之前發生(且不會注意到)。

先前的行為

先前,啟用 IncrementingPollingCounter 時,第一次叫用回呼可能會在執行啟用作業的執行緒上同步發生。

這個範例應用程式會在呼叫 EnableEvents() 內的 Main 線程上呼叫委派 () => SomeInterestingValue。 該回呼會觀察到 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",您可以將 ManualResetEvent 新增至 EventListener,在收到第一個計數器事件時發出訊號,並在呼叫 log.SomeInterestingValue++ 之前等候它。

受影響的 API