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

StackOverflow https://stackoverflow.com/questions/1631501

Вопрос

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

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

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

Это было полезно?

Решение

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

прочитайте этот чтобы добавить дополнительное расширение к секундомеру, например 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 to Sleep на ранее вычисленное значение uS/итерации, чтобы определить, сколько итераций цикла необходимо выполнить.
  • Вращайте с помощью цикла while, пока не истечет расчетное время.

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

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

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

    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);
        }
    }

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top