7

UIスレッドの使用状況を分析しようとしています。ディスパッチャによってキューに入れられたアイテムの数を照会することは可能ですか?

更新:クレメンスの回答は完全に機能しますが、UIの開始後にこれを開始したいので、データを1秒に1回だけサンプリングすることに注意して、次のコードを使用します...

        int queueLength = 0;
        var currentDispatcher = Dispatcher.CurrentDispatcher;
        currentDispatcher.Hooks.OperationPosted += (s, e) => Interlocked.Increment(ref queueLength);
        currentDispatcher.Hooks.OperationCompleted += (s, e) => Interlocked.Decrement(ref queueLength);
        currentDispatcher.Hooks.OperationAborted += (s, e) => Interlocked.Decrement(ref queueLength);
        Observable
            .Interval(TimeSpan.FromSeconds(1))
            .Subscribe(x =>
                           {
                               int currentQueueLength = queueLength;
                               if (currentQueueLength < 0)
                               {
                                   Interlocked.Add(ref queueLength, currentQueueLength * -1);
                               }
                               UiQueueLength = queueLength;
                           });
4

2 に答える 2

12

Afaikには、ディスパッチャキューの長さを直接要求できるプロパティやメソッドはありません。ただし、 Hooksプロパティによって提供されるDispatcherHooksイベントの一部にハンドラーをアタッチすることはできます。

var queueLength = 0;
Dispatcher.Hooks.OperationPosted += (o, e) => Interlocked.Increment(ref queueLength);
Dispatcher.Hooks.OperationStarted += (o, e) => Interlocked.Decrement(ref queueLength);
Dispatcher.Hooks.OperationAborted += (o, e) => Interlocked.Decrement(ref queueLength);

Dispatcherがアクティブであるかどうかだけに関心がある場合は、OperationPostedイベントをDispatcherInactiveと組み合わせて処理することができます。

于 2013-01-10T15:25:40.287 に答える
0

l上記のおかげで、ここに仕事をするためのクラスがあります:

/*
 This is for when you want to know the depth of the Dispatcher Queue an perhaps modifiy the behaviour of
 code to minimize impact like when data is comming into a TextBox faster that it can cope with.
  
 Usage:
 in MainWindow
 public DispatcherQueueLength dispatcherQueueLengthHelper;
 dispatcherQueueLengthHelper = new DispatcherQueueLength(App.Current.Dispatcher);
 dispatcherQueueLengthHelper.StartDispatcherHooks();
 in Loaded
 dispatcherQueueLengthHelper.StartUpdateTimer(new TimeSpan(0,0,0,1,0), DispatcherPriority.Send, () =>
    {
          App.mainVM.LblQueueCountContent = "UI Queue Count ~ " + dispatcherQueueLengthHelper.GetQueueLength.ToString("N0");
    });
 in Closing
 dispatcherQueueLengthHelper.EndDispatcherHooks();
 dispatcherQueueLengthHelper.EndUpdateTimer();
*/

public class DispatcherQueueLength
{
    private static int _queueLenth = 0;
    private Dispatcher _dispatcher = null;
    private DispatcherTimer _dispatcherTimer = null;

    /// <summary>
    /// Usually pass in App.Current.Dispatcher
    /// </summary>
    /// <param name="passedDispatcher"></param>
    public DispatcherQueueLength(Dispatcher passedDispatcher)
    {
        _dispatcher = passedDispatcher;

    }

    
    /// <summary>
    /// Call as needed. It is possible to have a negative number like when pending Dispatches exist
    /// when starting the class, they are zeroed out.
    /// </summary>
    public int GetQueueLength
    {
        get 
        {
            int currentQueueLength = _queueLenth;
            if (currentQueueLength < 0)
            {
                Interlocked.Add(ref _queueLenth, currentQueueLength * -1); //this zeros it
            }

            return currentQueueLength;
        }
    }


    /// <summary>
    /// Call directly after instantiating the class
    /// </summary>
    public void StartDispatcherHooks()
    {
        if (_dispatcher != null)
        {
            _dispatcher.Hooks.OperationPosted += (s, e) =>
            {
                Interlocked.Increment(ref _queueLenth);
                Debug.WriteLine("Queue Length: " + _queueLenth.ToString());
            };
            _dispatcher.Hooks.OperationCompleted += (s, e) =>
            {
                Interlocked.Decrement(ref _queueLenth);
            };
            _dispatcher.Hooks.OperationAborted += (s, e) =>
            {
                Interlocked.Decrement(ref _queueLenth);
            };
        }
    }

    /// <summary>
    /// You pass in the code you want run on each interval
    /// </summary>
    /// <param name="ts"></param>
    /// <param name="priority"></param>
    /// <param name="action"></param>
    public void StartUpdateTimer(TimeSpan ts, DispatcherPriority priority, Action action)
    {
        if(_dispatcherTimer == null)
        {
            _dispatcherTimer = new DispatcherTimer(priority);
            _dispatcherTimer.Tick += (s,e) => { action(); };
            _dispatcherTimer.Interval = ts;
            _dispatcherTimer.IsEnabled = true;
        }

    }

    /// <summary>
    /// Call in MainWindow Closing
    /// </summary>
    public void EndDispatcherHooks()
    {
        if(_dispatcher != null)
        {
            _dispatcher.Hooks.OperationPosted -= (s, e) => Interlocked.Increment(ref _queueLenth);
            _dispatcher.Hooks.OperationCompleted -= (s, e) => Interlocked.Decrement(ref _queueLenth);
            _dispatcher.Hooks.OperationAborted -= (s, e) => Interlocked.Decrement(ref _queueLenth);
        }
       
    }

    //Call in MainWindow Closing or if no longer needed
    public void EndUpdateTimer()
    {
        _dispatcherTimer.Stop();
        _dispatcher = null;

    }


}
于 2021-06-06T22:58:24.447 に答える