Как ограничить / уменьшить пропускную способность при * нескольких * подключениях - PullRequest
4 голосов
/ 19 мая 2009

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

Для одного соединения решение будет простым; Я бы использовал решение, опубликованное здесь: http://www.codeproject.com/KB/IP/Bandwidth_throttling.aspx который рассчитывает время ожидания для одного соединения.

Я хотел бы знать, как лучше всего это сделать для нескольких соединений.

Использование ThrottledStream, опубликованного выше, и равномерное распределение полосы пропускания (скажем, 2 МБ / с) между соединениями не является правильным, если бы у меня было 3 очень медленных соединения и 1 очень быстрое, все они были бы ограничены до 512 КБ / сек, поэтому быстрая скорость не превысит 512 кбит / с, а остальные 3 даже не сделают этого.

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

Кто-нибудь имеет опыт работы с этим, примером кода или любым советом?

Ответы [ 5 ]

3 голосов
/ 19 мая 2009

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

Total Bandwidth Allowed: 100KB/Sec
Connections : 5
Initial per-connection limit: 20KB/sec

Actual Results:
Connection 1: 10KB/sec
Connection 2: 5KB/sec
Connection 3: 20KB/sec
Connection 3: 20KB/sec
Connection 3: 20KB/sec

Total Short: 15KB/sec

New Per-Connection Limits:
Connection 1: 10KB/sec
Connection 2: 5KB/sec
Connection 3: 25KB/sec
Connection 3: 25KB/sec
Connection 3: 25KB/sec

Затем вы будете отслеживать это через некоторый интервал.

2 голосов
/ 19 мая 2009

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

Поскольку ваш сборщик ограничен совокупными данными / временем, вы получите правильную пропускную способность на стороне клиента.

0 голосов
/ 22 апреля 2011

С небольшой настройкой вы можете использовать класс, который вы указали в первом посте, поместить Throttle и Reset в статический класс.

0 голосов
/ 21 апреля 2010

У меня такая же проблема. Я пробую VS2010 Pro, и я сделал небольшой домашний проект, где я загружаю несколько файлов (10-50) одновременно, и я хочу ограничить пропускную способность для всех них. Я нашел эту публикацию, но я не могу найти решение, поэтому я попробовал для себя.

Я создал класс DownloadLimiter, который построен очень просто. Каждый раз, когда Загрузчик хочет загрузить чанк (например, непосредственно перед InputStream.Read ()), он должен запросить у DownloadLimiter пропускную способность. У него есть переменная, которая содержит ограничение, например, 50 000 (например, bytesPerSecond) и availableBandwidthPerSecond, которая уменьшается при обработке и возврате каждой функции ask ().

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

Метод ask () заблокирован, поэтому, если на данный момент нет доступной пропускной способности, он просто зацикливается и спит некоторое время, пока таймер не сбросит доступную пропускную способность.

Работает отлично, однако. Есть проблема. Допустим, у вас довольно быстрое соединение (100 мегабит), и вы установили ограничение в 200 КБ. Если вы загрузите один файл (из аналогичного быстрого соединения), то вы достигнете пика в 100 мегабит за x миллисекунд, а затем он будет ждать, пока доступная пропускная способность не будет сброшена. И это будет продолжаться, пока файл не будет завершен. Средняя скорость загрузки будет достаточно равномерной, но если вы посмотрите график пропускной способности, он будет иметь пики каждую секунду. Я полагаю, что опубликованная ссылка на ThrottledStream работает с пиком точно так же.

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

0 голосов
/ 12 июля 2009

Общее короткое выше на самом деле составляет 25 КБ / с, но вместо того, чтобы разделять соединения на группы, я бы сортировал по скорости и проходил по ним. Начните с общей пропускной способности и установите новую пропускную способность (оставшаяся пропускная способность / оставшееся количество). Это позволит сохранить ограничения для соединений 5k и 10k в случае их ускорения. Вы можете использовать выделенную полосу пропускания, но исправите ее.

List<Connection> connections = GetConnections();
connections.Sort(); // sorts by Speed
bandwidth = 100000;
for (int i = 0; i < connections.Count; i++)
{
    Connection cnn = connections[i];
    cnn.SpeedLimit = bandwidth / (connections.Count - i);
    bandwidth -= Math.Min(cnn.Speed, cnn.SpeedLimit);
}

(start with all connections SpeedLimit set to 20000 bytes/sec)

Speed   bandwidth SpeedLimit
5000    100000  20000
10000   95000   23750
20000   85000   28333
20000   65000   32500
20000   45000   45000

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

Скорость соединения изменяется на: 5000, 10000, 28333, 21000, 45000, поэтому мы фактически загрузили 109333 байта, но мы снова настроимся. Все соединения кроме 45k достигли своих возможных пределов:

Speed   bandwidth SpeedLimit
5000    100000  20000
10000   95000   23750
21000   85000   28333
28333   64000   32000
45000   35667   35667 

Новые скорости будут 5000, 10000, 21000, 28333, 35667, 100k точно

Speed   bandwidth SpeedLimit
5000    100000  20000
10000   95000   23750
21000   85000   28333
28333   64000   32000
35667   35667   35667

Теперь давайте предположим, что скорость соединения 5k до 20k:

Speed   bandwidth SpeedLimit
10000   100000  20000
20000   90000   22500
21000   70000   23333
28333   49000   24500
35667   20667   20667
...