Как вы ограничиваете скорость операций ввода-вывода? - PullRequest
5 голосов
/ 18 сентября 2008

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

Ответы [ 8 ]

16 голосов
/ 18 сентября 2008

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

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

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

4 голосов
/ 18 сентября 2008

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

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

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

1 голос
/ 18 сентября 2008

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

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

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

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

1 голос
/ 18 сентября 2008

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

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

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

ReadFixedRate() {
  while(Data_Exists()) {
    t = GetTime();
    ReadBlock();
    while(t + delay > GetTime()) {
      Delay()'
    }
  }
}
0 голосов
/ 05 мая 2011

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

0 голосов
/ 18 сентября 2008

Добавить к ответу Бранана:

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

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

0 голосов
/ 18 сентября 2008

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

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

0 голосов
/ 18 сентября 2008

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

Обратите внимание, что Wget реализует ограничение спя соответствующее количество время после чтения сети, что заняло меньше времени, чем указано в темп. В конечном итоге эта стратегия вызывает передача TCP замедляется до примерно указанная ставка. Тем не менее, это может занять некоторое время для этот баланс должен быть достигнут, так что не удивляйтесь, если ограничите скорость плохо работает с очень маленьким файлы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...