我可以使这个TimerQueueTimer类更高效吗?

时间:2011-05-11 05:01:30

标签: c# performance timer

using System;
using System.Threading;

internal class TimerQueueTimer : IDisposable
{
    public TimerQueueTimer(int interval, int msBeforeFirstCall)
    {
        this.interval = interval;
        this.msBeforeFirstCall = msBeforeFirstCall;
        this.callback = this.ticked;
        this.isTheFirstTick = true;
        this.isStopped = true;
    }

    public event EventHandler Ticked;

    public void Start()
    {
        if (!this.isStopped)
        {
            return;
        }

        this.isTheFirstTick = true;
        this.isStopped = false;
        Computer.ChangeTimerResolutionTo(1);
        NativeMethods.CreateTimerQueueTimer(
            out this.handle,
            IntPtr.Zero,
            this.callback,
            IntPtr.Zero,
            (uint)this.msBeforeFirstCall,
            (uint)this.interval,
            CallbackExecution.ExecuteInTimerThread);
    }

    public void Stop()
    {
        if (this.isStopped)
        {
            return;
        }

        NativeMethods.DeleteTimerQueueTimer(
            IntPtr.Zero,
            this.handle,
            IntPtr.Zero);
        Computer.ClearTimerResolutionChangeTo(1);
        this.isStopped = true;
    }

    public void Dispose()
    {
        this.Stop();
    }

    private void ticked(IntPtr parameterPointer, bool timerOrWaitFired)
    {
        if (this.isStopped)
        {
            return;
        }

        if (this.isTheFirstTick)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
        }

        this.isTheFirstTick = false;
        var ticked = this.Ticked;
        if (ticked != null)
        {
            ticked(this, EventArgs.Empty);
        }
    }

    private IntPtr handle;
    private volatile bool isStopped;
    private volatile bool isTheFirstTick;
    private readonly WaitOrTimerDelegate callback;
    private readonly int interval;
    private readonly int msBeforeFirstCall;
}

(注意:Computer.ChangeTimerResolutionTo()Computer.ClearTimerResolutionChangeTo()分别致电timeBeginPeriodtimeEndPeriod。)

问题:

  1. 回调正在计时器的线程中运行,而不是在ThreadPool线程中运行。只要回调函数很快就可以了,对吧?
  2. 将回调线程(以及定时器线程)优先级设置为Highest在性能方面做了什么吗?
  3. 将计时器间隔设为1ms并计算滴答数会更好,如果Ticked则提高tickCount % interval == 0吗?较低的间隔计时器是否更准确和精确?
  4. 是否有任何理由可能不如同样创建的timeSetEvent计时器准确和/或精确?
  5. 我问的原因是因为我们遇到了定时器回调问题,当系统负载很重时,偶尔会延迟最多约50ms。与我们以前使用timeSetEvent时相比,我觉得这种情况发生的次数较少 - 尽管这可能只是一种幻觉。我知道Windows不是确定性的,所以我只能这么做。但是,我想确保我已尽我所能,尽可能地将其作为高优先级。还有什么我可以做的吗?

1 个答案:

答案 0 :(得分:0)

我使用优先级队列来解决这个问题:队列的每个元素都包含回调地址(定时器例程),指向回调参数的指针以及将来应该触发的时间。

'time'是优先级,这里的逻辑是有可能从另一个线程唤醒定时器线程。当回调由另一个线程添加到队列时,定时器线程将被唤醒并且它寻找优先级队列的顶部元素,计算当前时间与存储在队列中的“时间”之间的差异并休眠直到计算的超时超过。

当超时唤醒定时器线程时,它从线程池启动新线程,调用回调。

我有一个计时器队列实现here,它没有经过良好测试,但你可以看看它是否有帮助。