我正在尝试分析UI线程的用法。是否可以查询调度员排队的项目数量?
更新:克莱门斯的答案非常有效,但是因为我想在UI启动后启动它,我只关心每秒采样一次,我使用以下代码... < / p>
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;
});
答案 0 :(得分:9)
Afaik没有可以直接询问调度程序队列长度的属性或方法。但是,您可以将处理程序附加到DispatcherHooks属性提供的某些Hooks事件中。
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事件。
答案 1 :(得分: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;
}
}