繁体   English   中英

当计时器线程没有按时完成时会发生什么

[英]What happens when timer threads don't finish on time

我正在使用System.Threading计时器来轮询不同线程上的传感器(由于通信延迟,一次一个很慢)。 它还允许用户通过更改计时器周期来更改轮询速率。

如果计时器在下一个时期之前没有完成,那么我无法解决的问题是什么。 我写了一个测试程序,但它没有真正回答任何问题。

如果我有一个运行大约需要1.7秒并且每10秒调用一次的函数,它会在下一个启动之前完成,并且我的CPU使用率在13%(一个核心100%)和0%之间波动。

t = new Timer(doWork, null, 0, 10000);

private void doWork(object o)
{
    for(int i = 0; i < numberItts; i++)
    {
    }
}

如果我然后将计时器周期降低到1秒,我会期望它在前一个线程完成之前不执行线程,或者继续生成新线程,并且随着更多线程在其他完成之前启动,CPU使用率将会上升。 实际发生的是CPU使用率在13%到25%之间波动。

将周期更改为500毫秒,CPU使用率将在38%和50%之间波动。 当然,在这一点上,他们应该比他们结束时更快地开始。

这些线程是如何管理的? 当轮询速率快于完成线程的速率时,限制创建的数量是多少?

System.Windows.Forms.Timer不同, System.Threading.Timer使用线程池 ,如果您的计时器处理程序需要比计时器间隔更长的时间,则不会被阻止。

因此,如果您的doWork需要大约“~1.7s”才能完成并且您的计时器间隔为1秒,您可能会看到多个并发线程进入doWork

这些线程是如何管理的? 当轮询速率快于完成线程的速率时,限制创建的数量是多少?

这一切都由Timer类和相关的线程池处理。

MSDN有这样的说法:

由计时器执行的回调方法应该是可重入的,因为它是在ThreadPool线程上调用的。 如果定时器间隔小于执行回调所需的时间,或者所有线程池线程都在使用且回调多次排队,则可以在两个线程池线程上同时执行回调。 更多...

因此,给定这段代码,其中定时器间隔为2秒,处理程序处理时间为1秒,我们可以期望每次都使用相同的线程,因为通常更好地重用相同的线程而不是启动新的线程:

class Program
{
    static void Main(string[] args)
    {
        var t = new Timer(doWork, null, 0, 1000);


        Console.WriteLine("Press any key to quit");
        Console.ReadKey();
    }

    private static void doWork(object o)
    {
        Console.WriteLine("Thread: {0}", Environment.CurrentManagedThreadId);

        // simulate lengthy process
        Thread.Sleep(1000);
    }
}

在此输入图像描述

将间隔和处理时间更改为1秒,由于轻微重叠导致随机线程。

在此输入图像描述

将间隔更改为200毫秒并将处理时间保持为1秒会导致工作线程数量比以前更多。 原因是线程池已经意识到委托的完成时间比定时器间隔要长,所以它试图跟上:

在此输入图像描述

我认为以下1s的计时器周期发生以下情况:

  • 在0秒:线程1启动。 一个处理器忙 - > ~13%
  • 在1秒钟:线程2启动。 两个处理器忙 - > ~25%
  • 在1.7秒:线程1完成。 只有一个处理器忙 - > ~13%
  • 在2秒时:启动线程3。 两个处理器忙 - > ~25%
  • 在2.7秒:线程2完成。 只有一个处理器忙 - > ~13%
  • ...

即,线程的处理速度比创建时快。 即使是500毫秒也是如此。

我认为当你将定时器周期减少到一个<1.7s / 8 = ~0.2125s的值时,你会发生预期的行为(假设有8个处理器可用,除了处理你的线程需要1.7s之外什么都不做。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM