【问题标题】:Stored values send to Console in different time intervals存储的值以不同的时间间隔发送到控制台
【发布时间】:2018-01-22 14:35:44
【问题描述】:

I've figured out how to store Data from a .csv to a List<>.

我有两个列表:ListA 包含每个值的时间戳,ListB 包含值。

看起来像这样:

A (time [ms])  | B (value)
---------------------------
0,00           | 49,33
154,71         | 49,46
244,92         | 49,72
855,11         | 49,64

...
And so on (over 50.000 values)

我的实际问题是: 我想在(几乎)准确的时间使用WriteLine(listA[i]); 将值发送到控制台,就像实际值的时间戳一样。

我想到了一个秒表,我将它与时间戳进行比较以在正确的时刻给出正确的值?

这可能吗?


更新 #1:

这是我的代码。它有效(有点)。但我不确定是否有更好的解决方案?

stopwatch.Start();

while(true)
{ 
    for (int i = 0; i < 50000; i++)
    {
        if (Math.Abs(stopwatch.Elapsed.TotalMilliseconds - Convert.ToDouble(listA[i]) * 1000) < 10)
        {
            Console.WriteLine(listB[i]);
        }
    }
    Thread.Sleep(5);
}

更新 #2:

我正在尝试了解 Mong Zhu @disclaimer 的解决方案。 我的目标是创建一个由计时器启动的方法(例如每 100 毫秒)。我已经有围绕这个问题的代码是:时间戳和秒表有时不同步,它会跳过一些值。

这是我的方法(每 100 毫秒调用一次):

public double getvalue()
    {

        if (stopwatch.ElapsedMilliseconds > Convert.ToDouble(ListA[ListA.Count-1])*1000)
        {
            stopwatch.Stop();
        }
        else
        {
            for (var i = 0; i < ListA.Count; i++)
            {
                if (Math.Abs(stopwatch.ElapsedMilliseconds - Convert.ToDouble(ListA[i]) * 1000) < 5)
                {
                    value = Convert.ToDouble(ListB[i]);
                    break;
                }
            }
        }

        return value;
    }

【问题讨论】:

  • 时间戳的维度是多少?那些秒、毫秒或纳秒?如果它不是太小,则计时器可能几乎精确(对于给定的“几乎”值)。
  • 简短回答:是的。尽管855,11 毫秒的分辨率可能很难实现。但不幸的是,这不是一个代码编写服务。请提供您编写的至少尝试解决问题的代码。描述你到底在哪里卡住了,我们可以帮助你。到目前为止,这个问题过于宽泛,可能因此而被关闭。
  • @RenéVogt 维度是毫秒。 “这不是代码编写服务”是什么意思?
  • 我的意思是,在您的第一篇文章中,您只是提出了一个需要解决的问题,而没有任何代码表明您试图自己解决它。现在帖子看起来不同了,我们可以开始解决您解决方案中的问题。我会更改顺序或forwhile 循环。您也可以使用Timer。给我一分钟,然后我写一个答案
  • 更正:维度是秒。

标签: c# list csv timestamp stopwatch


【解决方案1】:

如果你想使用StopWatch,那么我会切换forwhile 循环。只有在超出时间间隔并将值写入控制台后才迭代到下一个位置。这是一个示例程序:

void Main()
{
    Stopwatch stopWatch = new Stopwatch();
    List<int> ListA = new List<int>() { 0, 154, 244, 855 };
    List<double> ListB = new List<double>() { 49.33, 49.46, 49.72, 49.64 };

    stopWatch.Start();

    for (int i = 0; i < ListA.Count; i++)
    {
        while (stopWatch.ElapsedMilliseconds < ListA[i] * 1000) 
        {
            Thread.Sleep(5); 
         }

        Console.WriteLine($"Value: {ListB[i]} TIME: {stopWatch.ElapsedMilliseconds}");
    }

    stopWatch.Stop();

    Console.ReadKey();
}

代码中的问题:

1) for (int i = 0; i &lt; 50000; i++)
如果您遍历集合,最好不要为 for 循环使用固定数字。集合的大小可能会发生变化,并且固定数字将导致超出范围的异常或未处理的值。如果是List,则使用Count;如果是数组,则使用Length

2) 在每次迭代中,您都在迭代整个数组。如果您真的想按值打印,这是一个很大的开销。

免责声明。我的解决方案中的while 循环称为buisy-waiting。这并不是真正可取的,因为 CPU 被占用而实际上什么都不做。更好的解决方案是使用计时器:

System.Timers.Timer timer = new System.Timers.Timer();
// register the event which will be fired
timer.Elapsed += PrintValuesAtTime;
timer.Interval = 1; // an intervall of 0 is not allowed
timer.AutoReset = true; // repeated execution of the timer
timer.Start(); // start the timer

Console.ReadLine();

我将创建一个新列表,其中包含与 ListA 的所有时间戳差异,可用作下一次打印的间隔。比如:

List<int> ListAIntervals = new List<int>() { 0, 154-0, 244-154, 855-244 };

Elapsed 事件处理程序中,您可以处理打印逻辑。您需要一个外部计数器来遍历您的集合:

private void PrintValuesAtTime(object sender, EventArgs args)
{
    System.Timers.Timer timer = sender as System.Timers.Timer;
    // only print values if there are enough values
    if (counter < ListAIntervals.Count && counter < ListB.Count)
    {
        Console.WriteLine($"Value: {ListB[counter]}");
        // there needs to be enough intervals left to go one more time
        if (counter < ListAIntervals.Count - 1 && counter < ListB.Count - 1) 
        {
            counter++;
            timer.Interval = ListAIntervals[counter] * 1000; // to make it in msec
        }
        else
        {
            // stop the timer
            timer.AutoReset = false;
        }
    }       
}

【讨论】:

  • 1) 是的,你是对的。我还在学习 C# :)。 2) 是的。我想了想,但此刻我很高兴它起作用了。您的解决方案产生的开销更少。 3) 因子 1000 是复制/粘贴错误。列表中的值是秒,但有三位小数。
  • 我还能用吗?线程.睡眠(5)?没有它的 cpu 负载约为 25%。
  • 如果值以秒为单位,那么您应该删除您的评论“维度是毫秒。”
  • 当然你可以使用睡眠功能,我认为如果你使用它你会错过时间值,但由于值以秒为单位,我觉得很好。
  • 好的,谢谢。我试图了解您的解决方案@disclaimer。我的目标是创建一个由计时器启动的方法(例如每 100 毫秒)。我已经有了这方面的代码。我将发布我目前正在使用的实际解决方案(方法)。问题是:时间戳和秒表有时不同步,它会跳过一些值。
【解决方案2】:

如果您只有一个所需类型的列表,而不是两个单独的列表,那么您的实现会容易得多。让我解释一下:

您创建一个具有所需属性的类:

public class YourClass
{
     public long TimeMS {get; set;}
     public Double Value {get; set;}
}

然后你可以简单地创建一个List&lt;YourClass&gt;

List<YourClass> list = new List<YourClass>();

list.Add( new YourClass { TimeMS = 154.71, Value = 49.46 } );

那么迭代会容易得多:

foreach(YourClass c in list)
{
     //DO ALL YOUR WORK
     Console.WriteLine(c.TimeMS.ToString() + ": " + c.Value.ToString());
}

【讨论】:

  • 不错的解决方案,但我猜你错过了重点:“我想在(几乎)确切的时间像时间戳一样将值发送到控制台 (.WriteLine(listA[i]);)的实际价值。”时间戳应该告诉你什么时候你写的值
猜你喜欢
  • 2021-04-17
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
  • 2016-07-05
  • 2019-07-11
相关资源
最近更新 更多