Требуется микросекундная задержка в приложении.NET для регулирования скорости многоадресной передачи UDP

Я пишу пару клиент-сервер UDP многоадресной передачи в C#, и мне нужно задержка порядка 50-100 мкс (микросекунд), чтобы снизить скорость передачи сервера. Это помогает избежать значительной потери пакетов, а также помогает избежать перегрузки клиентов, связанных с дисковым вводом / выводом. Пожалуйста, не предлагайте Thread.Sleep или Thread.SpinWait. Я бы не спросил, нужен ли мне какой-либо из них.

Моей первой мыслью было использовать какой-то высокопроизводительный счетчик и выполнить простой цикл while(), проверяя истекшее время, но я бы хотел этого избежать, так как это кажется грязным. Не приведет ли это также к загрузке ЦП для серверного процесса?

Бонусные баллы за кроссплатформенное решение, то есть не для Windows. Заранее спасибо, ребята!

6 ответов

Решение

Я бы использовал секундомер, но нужна была бы петля

Прочитайте это, чтобы добавить дополнительное расширение к секундомеру, например ElapsedMicroseconds

или что-то подобное может работать тоже

System.Diagnostics.Stopwatch.IsHighResolution ДОЛЖЕН быть верным

    static void Main(string[] args)
    {
        Stopwatch sw;
        sw = Stopwatch.StartNew();
        int i = 0;

        while (sw.ElapsedMilliseconds <= 5000)
        {
            if (sw.Elapsed.Ticks % 100 == 0)
            { i++; /* do something*/ }
        }
        sw.Stop();


    }

Очень короткое время ожидания обычно лучше всего достигается с помощью цикла вращения процессора (например, типа, который вы описываете). Как правило, вы хотите избегать использования высокоточных вызовов таймера, поскольку они сами могут занять время и исказить результаты. Я бы не стал слишком беспокоиться о привязке ЦП на сервере при столь коротком времени ожидания.

Я бы инкапсулировал поведение в классе следующим образом:

  • Создайте класс, статический конструктор которого запускает цикл вращения в течение нескольких миллионов итераций и фиксирует, сколько времени это займет. Это дает вам представление о том, сколько времени займет один цикл цикла на базовом оборудовании.
  • Вычислите значение uS/ итерации, которое вы можете использовать для вычисления произвольного времени ожидания.
  • Когда его просят в течение определенного периода времени, разделите uS для сна на значение uS/ итерации, предварительно вычисленное, чтобы определить, сколько итераций цикла нужно выполнить.
  • Вращайте, используя цикл while, пока не истечет расчетное время.
    static void udelay(long us)
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        long v = (us * System.Diagnostics.Stopwatch.Frequency )/ 1000000;
        while (sw.ElapsedTicks < v)
        {
        }
    }
    static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine("" + i + " " + DateTime.Now.Second + "." + DateTime.Now.Millisecond);
            udelay(1000000);
        }
    }

Я столкнулся с таким требованием, когда мне нужно было больше точности с моим многоадресным приложением.

Я обнаружил, что лучшее решение - это таймеры MultiMedia, как показано в этом примере.

Я использовал эту реализацию и добавил к ней асинхронный вызов TPL. Вы должны увидеть мой проект https://github.com/eranbetzalel/SimpleMulticastAnalyzer для получения дополнительной информации.

Я бы не рекомендовал использовать спиновый цикл, поскольку он потребляет и создает блокирующий поток. Thread.sleep лучше, он не использует ресурсы процессора во время сна, он просто отрезает время. Попробуйте, и из диспетчера задач вы увидите, как загрузка ЦП резко возрастает с циклом вращения.

Вы смотрели на мультимедийные таймеры? Возможно, вы могли бы найти где-нибудь библиотеку.NET, которая где-то оборачивает вызовы API

Другие вопросы по тегам