Сохраненные значения отправляются в консоль через разные промежутки времени

Я понял, как хранить Данные из .csv в список‹>.

У меня есть два списка: 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;
    }

person William    schedule 22.01.2018    source источник
comment
Каков размер временной метки? Это секунды, миллисекунды или наносекунды? Если он не слишком мал, таймер может быть почти точным (для заданного значения почти).   -  person René Vogt    schedule 22.01.2018
comment
короткий ответ: ДА. Хотя разрешение в 855,11 миллисекунды может быть труднодостижимо. Но, к сожалению, это не служба написания кода. Пожалуйста, предоставьте код, который вы написали, который хотя бы пытается решить проблему. Опишите, где именно вы застряли, и мы сможем вам помочь. До сих пор вопрос слишком широк и может быть закрыт по этой причине.   -  person Mong Zhu    schedule 22.01.2018
comment
@RenéVogt размерность миллисекунды. Что вы имеете в виду, говоря, что это не служба написания кода?   -  person William    schedule 23.01.2018
comment
Я имел в виду, что в своем первом сообщении вы просто представили проблему, которую нужно решить, без какого-либо кода, который показывает попытку решить ее самостоятельно. Теперь пост выглядит иначе, и мы можем приступить к решению проблем в вашем решении. Я бы изменил порядок или цикл for и while. Вы также можете использовать Timer. Дайте мне минуту, тогда я напишу ответ   -  person Mong Zhu    schedule 23.01.2018
comment
Исправление: измерение секунд.   -  person William    schedule 23.01.2018
comment
Я также изменил это в вашем посте List A (time in sec)   -  person Mong Zhu    schedule 23.01.2018


Ответы (2)


Если вы хотите использовать StopWatch, я бы поменял местами цикл for и while. Переходите к следующей позиции только после того, как вы превысили временной интервал и записали значение в консоль. Вот примерная программа:

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 < 50000; i++)
Желательно не использовать фиксированное число для цикла for, если вы перебираете коллекцию. Размер коллекции может измениться, а фиксированное число приведет либо к исключению за пределы допустимого диапазона, либо к необработанным значениям. Используйте Count, если это List, или Length, если это массив

2) В каждой итерации вы перебираете весь массив. Это большие накладные расходы, если вы действительно хотите печатать значение за значением.

Отказ от ответственности. Цикл while в моем решении называется ожиданием занятости. На самом деле это не рекомендуется, так как ЦП занят, а на самом деле ничего не делает. Предпочтительным решением было бы использование таймера:

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;
        }
    }       
}
person Mong Zhu    schedule 23.01.2018
comment
1) Да, вы правы. Я все еще изучаю С# :). 2) Ага. Я думал об этом, но в этот момент я был счастлив, что это работает. Ваше решение производит меньше накладных расходов. 3) Фактор 1000 был ошибкой копирования/вставки. Значения в списке — это секунды, но с тремя десятичными знаками. - person William; 23.01.2018
comment
Могу ли я все еще использовать, например. Thread.Sleep(5) ? Загрузка процессора без него составляет около 25%. - person William; 23.01.2018
comment
если значения указаны в секундах, вы должны удалить свой комментарий, размер которого составляет миллисекунды. - person Mong Zhu; 23.01.2018
comment
конечно, вы можете использовать функцию сна, я думал, что вы пропустите значения времени, если будете ее использовать, но, поскольку значения указаны в секундах, мне кажется, это нормально. - person Mong Zhu; 23.01.2018
comment
хорошо, спасибо. Я пытаюсь понять ваше решение @disclaimer. Моя цель - создать метод, который инициируется таймером (например, каждые 100 мс). У меня уже есть код вокруг этого. Я опубликую свое фактическое решение (метод), которое я использую в данный момент. Проблема в том, что метка времени и секундомер иногда не синхронизируются и пропускают некоторые значения. - person William; 23.01.2018
comment
почему вы пытаетесь вызывать метод каждые 100 мс? Если вы хотите использовать секундомер, вам нужно выполнить ожидание в цикле while. Таким образом, он повторяется почти каждую миллисекунду. В противном случае используйте Timer и установите интервал точно на время, которое вам нужно рассчитать из вашего списка, как я показал во втором примере. StopWatch это не таймер! это секундомер ;) - person Mong Zhu; 23.01.2018
comment
Я называю это, когда мне нужно мое значение. 100 мс - это только пример. Хорошо, я попробую с таймером вместо секундомера. - person William; 24.01.2018

Ваша реализация была бы намного проще, если бы вместо двух отдельных списков у вас был только один список нужного вам типа. Позволь мне объяснить:

Вы создаете класс с нужными вам свойствами:

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

Затем вы можете просто создать List<YourClass>

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());
}
person NicoRiff    schedule 22.01.2018
comment
хорошее решение, но я думаю, вы упустили суть: я хочу отправить значения на консоль (.WriteLine(listA[i]);) в (почти) точное время, как метка времени фактического значения. метка времени должна сообщать вам, когда вы записываете значение - person Mong Zhu; 22.01.2018