Timer.Elapsed 和 BeginInvoke 仍然落后于 GUI
Timer.Elapsed and BeginInvoke still lag GUI
有一段第 3 方 API 代码,SomeWork()
,需要每 3 秒 运行 来监控一些物理设备。我想使用 using System.Timers.Timer 并且它的 Elapse 事件是异步的,但它每 3 秒滞后一次我的 GUI 操作。我尝试使用 Dispatcher.BeginInvoke 执行 SomeWork()
但我在 GUI 上仍然遇到同样的滞后,即使 SomeWork()
实际上没有更新任何 GUI 并且不应该占用 GUI 线程。
private void StartTimerAtStartup()
{
System.Timers.Timer connTimer = new System.Timers.Timer();
connTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
connTimer.Interval = 3000;
connTimer.Enabled = true;
}
private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(DispatcherPriority.Send, (ElapsedEventHandler)MyTimer_Elapsed, sender, e);
return;
}
// Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(
// () => SomeWork())
// );
SomeWork();
}
[EDIT1]
如果我删除所有 Dispatcher 并直接调用 SomeWork() ,那么我会收到无法访问此线程的异常。
[EDIT2]
SomeWork() 是第 3 方 API 监听物理设备和接收数据包,不涉及 GUI。我尝试了各种方法来执行 Dispatcher.BeginInvoke,但遇到了以下我无法理解的问题。为什么使用 lamda 会滞后于 GUI 而执行委托不会滞后于 GUI?
// This lags the GUI
Dispatcher.BeginInvoke(new Action( () => SomeWork() ));
// This does not lag the GUI. Application runs smooth,
// but I do not understand why
Dispatcher.BeginInvoke((Action)delegate () { SomeWork(); });
你调用了GUI线程的Dispatcher。因此,BeginInvoke 将异步工作调用到 UI 线程,并且您的 UI 滞后。
您的计时器在与 UI 不同的线程中触发 Elapsed
事件。所以你可以简单地在事件处理程序中调用你的方法。
但是,如果您需要严格每 3 秒调用一次 API,那么您需要考虑执行 SomeWork 所需的时间或在单独的线程中完成该工作。然后你可以使用任务来实现它。
Task.Factory.StartNew(SomeWork);
但在这种情况下,您将不得不处理可能的竞争条件并同步您的工作。
有一段第 3 方 API 代码,SomeWork()
,需要每 3 秒 运行 来监控一些物理设备。我想使用 using System.Timers.Timer 并且它的 Elapse 事件是异步的,但它每 3 秒滞后一次我的 GUI 操作。我尝试使用 Dispatcher.BeginInvoke 执行 SomeWork()
但我在 GUI 上仍然遇到同样的滞后,即使 SomeWork()
实际上没有更新任何 GUI 并且不应该占用 GUI 线程。
private void StartTimerAtStartup()
{
System.Timers.Timer connTimer = new System.Timers.Timer();
connTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
connTimer.Interval = 3000;
connTimer.Enabled = true;
}
private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(DispatcherPriority.Send, (ElapsedEventHandler)MyTimer_Elapsed, sender, e);
return;
}
// Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(
// () => SomeWork())
// );
SomeWork();
}
[EDIT1]
如果我删除所有 Dispatcher 并直接调用 SomeWork() ,那么我会收到无法访问此线程的异常。
[EDIT2]
SomeWork() 是第 3 方 API 监听物理设备和接收数据包,不涉及 GUI。我尝试了各种方法来执行 Dispatcher.BeginInvoke,但遇到了以下我无法理解的问题。为什么使用 lamda 会滞后于 GUI 而执行委托不会滞后于 GUI?
// This lags the GUI
Dispatcher.BeginInvoke(new Action( () => SomeWork() ));
// This does not lag the GUI. Application runs smooth,
// but I do not understand why
Dispatcher.BeginInvoke((Action)delegate () { SomeWork(); });
你调用了GUI线程的Dispatcher。因此,BeginInvoke 将异步工作调用到 UI 线程,并且您的 UI 滞后。
您的计时器在与 UI 不同的线程中触发 Elapsed
事件。所以你可以简单地在事件处理程序中调用你的方法。
但是,如果您需要严格每 3 秒调用一次 API,那么您需要考虑执行 SomeWork 所需的时间或在单独的线程中完成该工作。然后你可以使用任务来实现它。
Task.Factory.StartNew(SomeWork);
但在这种情况下,您将不得不处理可能的竞争条件并同步您的工作。