代码之家  ›  专栏  ›  技术社区  ›  Nippysaurus

以精确的间隔执行代码

  •  0
  • Nippysaurus  · 技术社区  · 15 年前

    我有一个数据列表和需要处理的时间。时间通常间隔一秒(或更短)(它们会有所不同),但需要在相当接近的时间内运行。我试过让线程休眠一小段时间,但是在休眠后恢复线程会带来一些开销,这会导致短暂的延迟。有没有一种可靠的方法来获得相对简单的代码所需的准确性?

    5 回复  |  直到 15 年前
        1
  •  1
  •   stacked    15 年前

    尝试使用秒表对象。我创建了一个假设的数据和时间对象

    public class DataAndTime
    {   
       private string m_Data = "";
       public string Data {
          get { return m_Data; }
          set { m_Data = value; }
       }
    
       private int m_TimeInMilliSeconds = 0;
       public int TimeInMilliSeconds {
          get { return m_TimeInMilliSeconds; }
          set { m_TimeInMilliSeconds = value; }
       } 
    }
    

    其中TimeInMillises是要处理数据列表的精确间隔(毫秒)。然后我创建了两个对象,一个堆栈和一个秒表:

    private Stack<DataAndTime> aStack = new Stack<DataAndTime>();    
    private Stopwatch aStopWatch = new Stopwatch()
    

    您可以使用集合或列表,而不是堆栈或其他。我用100个数据和时间对象填充堆栈:

    public void PopulateStack{
        for (int Index = 0; Index <= 100; Index++) {
            DataAndTime NewDataAndTime = new DataAndTime();
            NewDataAndTime.Data = (string)Index + " AS A STRING";
            NewDataAndTime.TimeInMilliSeconds = 1000 - Index;
            aStack.Push(NewDataAndTime);
        }
     } 
    

    这个想法与停止和启动秒表的物理模拟是一样的,直到经过毫秒的相关时间后才做一些事情。瞧。总共约40行代码:

     public void ProcessData{
     {
         while (aStack.Count > 0) {
             aStopWatch.Reset();
             aStopWatch.Start();
             DataAndTime StackPop = aStack.Pop;
             string CallBackData = StackPop.Data;
             int CallBackTime = StackPop.TimeInMilliSeconds;
             while (aStopWatch.ElapsedMilliseconds < CallBackTime) {
             }
             Console.WriteLine("Time elapsed for " + CallBackData + " " + CallBackTime + ":  " + aStopWatch.ElapsedMilliseconds);
             aStopWatch.Stop();
         }
     }
    
        2
  •  2
  •   RossFabricant    15 年前

    在多任务操作系统中,提高进程的优先级是有帮助的,但是除非您的操作系统支持它。 real time 你不能用几毫秒的精度来保证时间。

        3
  •  1
  •   Christian C. Salvadó    15 年前

    用这个怎么样 System.Threading.Timer 单独线程上的类?

        4
  •  0
  •   James Black    15 年前

    如果您确实需要在时间上保持短时间的差异,那么您可能需要考虑使用DirectX API。Directx9.0c有一个托管的.NET接口,它允许您访问高可靠性时钟。我用这个播放了一些音乐,在那里我只有不到1毫秒的时间来开始和停止音乐,这个效果很好。

    但是,应用程序将接管计算机,因为共享会中断您的计时,那么您也可以使用计时器。

        5
  •  0
  •   Mark Rushakoff    15 年前

    最可靠的方法是在 准确的 你想要的时间,将被封锁到准确的时间。在伪代码中:

    futuretime = now + 1 second;
    while (now < futuretime)
    {
         // do nothing
    }
    // 1 second has elapsed, start processing
    

    当然,只要你在while循环中,这会占用CPU。

    或者你可以走到一半,做一个线程睡眠,直到你在目标时间的50毫秒以上,然后再做一个阻塞等待。你不会占用那么多的CPU,你可以合理地确定你的线程会在1秒到达之前被激活。

    This article 对Windows API提供的计时功能进行了非常全面的评估。最后得出结论:

    …考虑一个混合方案,你称之为睡眠(1)……当您需要通过超过1毫秒的时间时,只需输入queryperformanceCounter 100%busy循环即可完成所需延迟的最后1/1000秒。这将为您提供超精确的延迟(精确到10微秒),CPU使用率非常低。