Требуется микросекундная задержка в приложении.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