【问题标题】:How can I run a method every X microseconds without CPU loading (0 < X < 1000)?如何在不加载 CPU 的情况下每 X 微秒运行一个方法(0 < X < 1000)?
【发布时间】:2017-06-27 06:29:48
【问题描述】:

我正在寻找任何计时器的设计,它可以安排周期小于 1 毫秒的任务。 最佳方案:加载 1 个核心的 25%,当 1 个单独的线程用于运行时这种模式。

1 毫秒是所有计时器的限制,我知道:

  • System.Windows.Forms.Timer
  • System.Timers.Timer
  • System.Threading.Timer

我已经实现了计时器,它每 X 微秒运行一次任务。但是,当使用 1 个单独的线程来运行此模式时,它仍然几乎加载了一个内核。

代码:

private readonly TimeSpan _period;

private readonly Stopwatch _stopwatch;

private TimeSpan _lastElapsedTime;

private Double _iterationsPerPeriod;

void Run() 
{
    TimeSpan elapsed = _stopwatch.Elapsed;
    TimeSpan interval = elapsed - _lastElapsedTime;
    if (interval < _period)
    {
        Int32 iterationsToWait = (Int32) (_iterationsPerPeriod * (interval.TotalMilliseconds / _period.TotalMilliseconds));
        Thread.SpinWait(iterationsToWait);
    }

    _lastElapsedTime = _stopwatch.Elapsed;
    // RunTask();
}

void RunTimer() 
{
    while(true)
    {
        Run();
    }
}

如何在不加载 CPU 的情况下每 X 微秒运行一次方法?

【问题讨论】:

  • 您可以使用任务并行库。见msdn.microsoft.com/en-us/library/dd537609(v=vs.110).aspx........但是你需要使用.Net 4.0或以上版本
  • 不确定是否可以。 Windows 无法以这种速度切换您的线程,因此您的线程将仍在运行并消耗 CPU 时间。
  • @SureshKumarVeluswamy,谢谢。这似乎是一个替代方案。使用 TPL 将导致每秒多次分配。
  • @xanatos 它可以在 CPU 进行切换之前暂停 CPU 一段时间(这主要发生在定时器中断上,所以没问题),但这只会帮助使用电源,而不是其他正在运行的线程系统上。然后你必须等待其他线程放弃 CPU 才能再次运行,这根本不会发生。

标签: c# performance scheduled-tasks scheduling


【解决方案1】:

“停止” CPU 的唯一方法是停止它 - 这是 Windows 上的内核级指令。唤醒 CPU 的唯一方法是给它一个中断 - 再次,内核级别。虽然可以在 x86 上创建比毫秒精度高得多的计时器中断,但您需要创建自己的操作系统(可能是虚拟化的 - 如果它专门使用 CPU)来使用它。

在应用程序级别,您需要完全依赖可用的接口。而且您需要与在同一 CPU/OS 上运行的其他进程合作。这意味着您需要使用 OS 任务调度 - 而 Windows 任务调度有限制。您可能等待的最短时间间隔取决于操作系统允许的时间 - 在 Windows 上,这曾经与系统计时器有关(约 20 毫秒,可配置为 0.5 毫秒)。但即使使用较新的调度程序,您也不能随意调度线程以微秒精度运行。

如果您需要这种硬实时环境,您根本无法使用 Windows 或任何其他抢先式多任务系统,真的。每隔半毫秒休眠一次,已经在推动现代系统同时运行数百个进程和数千个线程的现实能力。如果您可以负担得起该线程几乎可以为自己占用 CPU,那么忙碌等待可以使您接近(实际上仍在游戏中使用)-否则,其他线程可以轻松地从您的线程中窃取 CPU(轻松 20 毫秒或更长时间)。当然,如果系统负载过大,它仍然会很快失败。

与往常一样,这是一场权衡取舍的游戏。制作一个可以如此精确地调度线程的现代多任务系统是可能的,但这并不值得。即使在具有独占 CPU 访问权限的旧游戏中,您通常也不会“睡眠 20us”——相反,您会等待垂直回溯中断或类似的东西(这在 DirectX/OpenGL/Vulkan 中仍然有些可用。. .)。很少有应用程序既需要现代多任务系统,又需要如此高的调度程序精度。在大多数用户应用程序中,您可以使用允许您在 25% 的时间内睡眠的算法 每 20us 切换一次线程上下文(例如,每“帧”做更多的工作,并相应地延长睡眠时间)。

【讨论】:

    猜你喜欢
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多