Как вы ограничиваете скорость операции ввода-вывода?

Предположим, у вас есть программа, которая читает из сокета. Как сохранить скорость загрузки ниже определенного порога?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
3 625
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Предполагая сетевой транспорт, основанный на TCP / IP, пакеты отправляются в ответ на пакеты ACK / NACK, идущие в обратном направлении.

Ограничивая скорость пакетов, подтверждающих получение входящих пакетов, вы, в свою очередь, уменьшаете скорость, с которой отправляются новые пакеты.

Это может быть немного неточно, поэтому, возможно, оптимально контролировать скорость нисходящего потока и адаптивно регулировать скорость отклика, пока она не упадет в комфортный порог. (Это произойдет очень быстро, однако вы отправляете несколько подтверждений в секунду)

Разве для этого не требуется переход к низкоуровневому стеку TCP / IP и обход стандартного уровня сокетов?

Branan 18.09.2008 22:05

Если вы читаете из сокета, у вас нет контроля над используемой полосой пропускания - вы читаете буфер операционной системы этого сокета, и ничто из того, что вы говорите, не заставит человека, записывающего в сокет, писать меньше данных (если, конечно, , вы разработали для этого протокол).

Все, что происходит при медленном чтении, - это заполнение буфера и возможная остановка на стороне сети - но вы не можете контролировать, как и когда это произойдет.

Если вы действительно хотите читать только определенное количество данных за раз, вы можете сделать что-то вроде этого:

ReadFixedRate() {
  while(Data_Exists()) {
    t = GetTime();
    ReadBlock();
    while(t + delay > GetTime()) {
      Delay()'
    }
  }
}

Буферы имеют максимальные значения. Кэш? Кеша нет.

Stu Thompson 18.09.2008 22:08

Вы, конечно, абсолютно правы. Я удалил кэш и добавил немного о буферах.

Branan 18.09.2008 22:23

Кажется, что wget справляется с этим с помощью опции --limit-rate. Вот со страницы руководства:

Note that Wget implements the limiting by sleeping the appropriate amount of time after a network read that took less time than specified by the rate. Eventually this strategy causes the TCP transfer to slow down to approximately the specified rate. However, it may take some time for this balance to be achieved, so don't be surprised if limiting the rate doesn't work well with very small files.

Ответ принят как подходящий

На прикладном уровне (используя API в стиле сокетов Беркли) вы просто смотрите на часы и читаете или записываете данные с той скоростью, которую вы хотите ограничить.

Если вы читаете в среднем только 10 кбит / с, но источник отправляет больше, то в конечном итоге все буферы между ним и вами заполнятся. TCP / IP позволяет это, и протокол будет организовывать замедление отправителя (на уровне приложения, вероятно, все, что вам нужно знать, это то, что на другом конце блокирующие вызовы записи будут блокироваться, неблокирующая запись завершится ошибкой и асинхронная запись не будет завершена, пока вы не прочитаете достаточно данных, чтобы это разрешить).

На прикладном уровне вы можете быть только приблизительными - вы не можете гарантировать жестких ограничений, таких как «не более 10 КБ пройдет через заданную точку в сети за одну секунду». Но если вы будете следить за тем, что получили, вы сможете получить среднее значение в долгосрочной перспективе.

Как уже говорили другие, ядро ​​ОС управляет трафиком, и вы просто читаете копию данных из памяти ядра. Чтобы примерно ограничить скорость всего одного приложения, вам нужно отложить чтение данных и позволить входящим пакетам буферизоваться в ядре, что в конечном итоге замедлит подтверждение входящих пакетов и снизит скорость на этом одном сокете.

Если вы хотите замедлить весь трафик на машину, вам нужно пойти и настроить размеры входящих TCP-буферов. В Linux вы можете повлиять на это изменение, изменив значения в / proc / sys / net / ipv4 / tcp_rmem (размеры буфера чтения памяти) и других файлах tcp_ *.

Это похоже на ограничение игры определенным количеством кадров в секунду.

extern int FPS;
....    
timePerFrameinMS = 1000/FPS;

while(1) {
time = getMilliseconds();
DrawScene();
time = getMilliseconds()-time;
if (time < timePerFrameinMS) {
   sleep(timePerFrameinMS - time);
}
}

Таким образом вы убедитесь, что частота обновления игры будет не выше FPS. Таким же образом DrawScene может быть функцией, используемой для перекачки байтов в поток сокета.

Чтобы добавить к ответу Бранана:

Если вы добровольно ограничите скорость чтения на стороне получателя, в конечном итоге очереди заполнятся на обоих концах. Затем отправитель либо заблокирует вызов send (), либо вернется из вызова send () с размером sent_length меньше ожидаемой длины, передаваемой вызову send ().

Если отправитель не готов справиться с этим случаем, засыпая и пытаясь повторно отправить то, что не помещается в буферы ОС, в конечном итоге у вас возникнут проблемы с подключением (отправитель может обнаружить это как ошибку) или потерять данные (отправитель может неосознанно отбросить данные, которые не поместились в буферы ОС).

Установите небольшие буферы отправки и получения сокета, скажем 1k или 2k, так, чтобы полоса пропускания * произведение задержки = размеру буфера. Возможно, вам не удастся сделать его достаточно маленьким по быстрым ссылкам.

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