WPF Task有时候会延迟进入,或者进入后到切换UI线程时会延迟进入。

2019-12-27 17:02发布

问题:

场景,定时器6S一次调用以下方法:代码大概如下:

我另外的业务需要暂停这个定时器,当重新启动定时器时,因为需要即时,所以没用定时器启动方法,而直接调用这个方法,方法内部运行完再启动这个定时器,有时候很慢才进入UI线程里面,保存数据完成后开始计算UI线程进入事件,大概30秒以上。这是线程在排队吗?我应该怎么优化我的代码?或者说我能否指定一个线程专门负责我的定时器,而不需要每次都开启一个线程?

public void GetShipLocation(int min)
{
if (StopTimer)
{
return;
}
ThreadPool.QueueUserWorkItem((o) =>
{
Task.Run(async () =>
{
getShipPositionTimer.Stop();
try
{
Console.WriteLine("Testing method: GetShipLocation " + DateTime.Now);
//读取数据
//保存数据
await App.MyDatabase.SaveVesselRecordListAsync(App.vesselRecordList);
await App.MyDatabase.SaveListWarningMessAsync(newWarnList);
Application.Current.Dispatcher.Invoke(() =>
{
//一些UI线程对象操作
});

                }
                catch (Exception ex)
                {


                }
                getShipPositionTimer.Start();
            });
        });
    }

回答1:

没看懂描述,
定时器6S一次调用GetShipLocation,
然后GetShipLocation里面又有对于定时器的Stop和Start?



回答2:

QueueUserWorkItem 里面的代码必要再用Task了。可能连QueueUserWorkItem都不用因为看这代码读数据和保存数据的方法都是异步的。方法在保存完数据后才会执行更新UI的代码啊,你可以在读数据前和更新UI前记录下时间看看间隔时间



回答3:

有一些问题

  1. 既然已经用了Task为什么用ThreadPool,Task.Run方法默认就是放到线程池上执行的,在ThreadPool中调用Task.Run好像没有什么意义。
  2. System.Threading.Timer 或者 System.Timers.Timer 本就是在单独的后台线程上执行的。
  3. 那两个Save方法有没有可能抛出异常,如果有,操作UI对象的代码可能无法执行。应该吧这段代码放到trycatch外面。
  4. 这个方法是定时器定期调用吗,如果是,在方法内部调用timer.start()好像有些不妥,应该放到外面去。