【问题标题】:Timer is delayed when many Tasks are running许多任务正在运行时计时器延迟
【发布时间】:2013-06-14 02:23:45
【问题描述】:

我正在使用 Timer 来计算动作进度,但是如果有很多正在运行的任务,则计时器会延迟。

下面是我的计时器类:

public class TimingAction
{
    private const int ProgressUpdateIntervalDefault = 500;

    public int Duration { get; set; }
    public int ProgressUpdateInterval { get; set; }

    public event Action<double> ProgressUpdated;

    private readonly Timer progressTimer = new Timer();
    private readonly Timer scanTimer = new Timer();
    private readonly Stopwatch timeWatch = new Stopwatch();

    public TimingAction()
    {
        ProgressUpdateInterval = ProgressUpdateIntervalDefault;
    }

    public void Start()
    {
        // Stop progress after duration time
        timeWatch.Restart();

        scanTimer.Interval = Duration;
        scanTimer.Elapsed += (o, e) => Stop();

        // Send progress notification
        progressTimer.Interval = ProgressUpdateInterval;
        progressTimer.Elapsed += (o, e) =>
        {
            if (ProgressUpdated != null)
            {
                ProgressUpdated((double)timeWatch.ElapsedMilliseconds / Duration);
            }
        };

        timeWatch.Start();
        scanTimer.Start();
        progressTimer.Start();
    }

    public void Stop()
    {
        scanTimer.Stop();
        progressTimer.Stop();
        timeWatch.Stop();
    }
}

下面是我的测试类:

class Program
{
    static void Main(string[] args)
    {
        int wt, ct;
        ThreadPool.GetAvailableThreads(out wt, out ct);
        Console.WriteLine("Before starting tasks : worker thread {0}, completion thread {1}", wt, ct);

        for (int i = 0; i < 5; i++)
        {
            int taskID = i;
            //Task.Factory.StartNew(() => TestTask(taskID));   
            var t = new Thread(() => TestTask(taskID));
            t.Start();
        }

        ThreadPool.GetAvailableThreads(out wt, out ct);
        Console.WriteLine("After starting tasks : worker thread {0}, completion thread {1}", wt, ct);

        var action = new TimingAction();
        action.ProgressUpdated += action_ProgressUpdated;
        action.ProgressUpdateInterval = 100;
        action.Duration = 1000;
        action.Start();

        Console.WriteLine("After starting timer : worker thread {0}, completion thread {1}", wt, ct);
        Console.ReadLine();
    }

    static void action_ProgressUpdated(double obj)
    {
        Console.WriteLine("progress {0:00}%", obj*100);
    }

    static void TestTask(int taskID)
    {
        while (true)
        {
            Thread.Sleep(1000);
            //Console.WriteLine("Thread ID: {0}, Task {1}", Thread.CurrentThread.ManagedThreadId, taskID);
        }
    }
}

当我使用 Thread 类运行 TestTask 方法时,进展顺利,结果是:

Before starting tasks : worker thread 1023, completion thread 1000
After starting tasks : worker thread 1023, completion thread 1000
After starting timer : worker thread 1023, completion thread 1000
progress 16%
progress 21%
progress 33%
progress 44%
progress 54%
progress 65%
progress 76%
progress 87%
progress 98%

但是当我使用Task类运行TestTask方法时,定时器Elapsed调用被延迟,结果是:

Before starting tasks : worker thread 1023, completion thread 1000
After starting tasks : worker thread 1019, completion thread 1000
After starting timer : worker thread 1019, completion thread 1000
progress 105%
progress 199%

这种延迟的原因是什么,无论如何要解决它?但是,延迟只发生在开始的 2 秒,如果我将持续时间增加到 10 秒,则延迟 2 秒后进度会很好。

应用程序在 .Net Framework 4.5 下运行。

【问题讨论】:

  • 延迟的可能不是计时器本身。回调需要在线程池线程上运行。如果他们都忙于运行其他任务,回调将被延迟。
  • @BrianRasmussen:我也认为它与 ThreadPool 有关。但我只运行了 5 个任务,它们总是在睡觉,它不应该影响定时器。

标签: c# timer task


【解决方案1】:

我无法确定您使用的是哪种类型的 Timer,因为我们看不到顶部的 using 语句......但我会假设它是 System.Windows.Forms.Timer .

This Microsoft article 解释了定时器之间的区别。如果您对何时触发计时器有严格要求,则使用 System.Timers.Timer 可能是更好的选择。

【讨论】:

  • 谢谢。我试过System.Timers.Timer和System.Threading.Timer,结果是一样的。
猜你喜欢
  • 2015-09-14
  • 1970-01-01
  • 2016-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-11
  • 2018-04-23
  • 1970-01-01
相关资源
最近更新 更多