Почему многопоточная загрузка быстрее, чем однопотоковая?
13
На моем сервере есть один большой файл. Я считаю, что многопоточная загрузка может получить 20 Мбит, но одна нить может получить 10 Мбит, кто-нибудь может объяснить это?
Несколько потоков, обслуживающих одно и то же TCP-соединение, или несколько потоков, каждый из которых имеет отдельные TCP-соединения? Также вы говорите, что сервер многопоточный, или клиент многопоточный, или оба?
Спифф
Ответы:
14
Обычно это происходит потому, что где-то между вами и другим сервером существует брандмауэр, ограничивающий каждый поток HTTP до 10 Мбит / с. Когда вы используете многопоточность, вы получаете 2x 10Mb (по одному для каждой нити).
Я использую FTP, и на моем сервере нет ограничений
почему
@ почему: может быть, твой интернет-провайдер ограничивает каждое соединение до 10 Мбит / с? Можете ли вы получить больше, чем в тестере скорости?
Андре Парамес
4
Это связано с вашим пингом между вами и сервером и размером окна / размера окна tcpip, используемого вашей загружаемой программой.
По сути, если у вас 100 мс на сервер и вы запрашиваете пакеты размером 100 Кб, вы можете получать только 10 пакетов в секунду, используя 1 соединение, даже если ваша скорость интернета бесконечна.
Вам не нужно подтверждать каждый пакет, пока получатель очищает свой буфер с разумной скоростью, отправитель должен иметь возможность постоянно их перекачивать.
Андре Парамес
Это верно. Но даже с буфером 256 КБ, ping все еще вызывает значительное замедление
BarsMonster,
3
TCP работает лучше всего, когда вы «держите канал заполненным» - когда отправляющее приложение продолжает посылать буферы достаточно быстро, чтобы стек TCP отправителя постоянно получал данные, так что он всегда мог иметь данные «в полете» в сети, и когда получатель приложение продолжает читать из получающего TCP-стека достаточно быстро, чтобы окно TCP получателя никогда не заполнялось (опять же, поэтому отправляющий TCP-стек всегда может сохранять данные «в полете» в сети).
Я мог бы представить плохо написанное однопоточное приложение отправителя, которое передает один буфер в стек TCP, ждет, когда он полностью Acked, а затем передает другой буфер. Это означает, что как только конец первого буфера «в полете» в сети, отправляющему стеку TCP не хватает данных для отправки, что означает, что канал истощается и не заполняется до тех пор, пока не вернется Ack и приложение-отправитель. передает ему новый буфер.
Я мог бы также представить плохо написанное однопоточное приложение-получатель, которое недостаточно быстро читает из принимающего TCP-стека и, таким образом, позволяет заполнять буферы TCP-стека, что означает, что окно TCP заполняется, что приводит к тому, что отправляющий TCP-стек прекратить отправку, пока не откроется окно. Увеличение размера окна TCP получателя может немного помочь, но реальным решением в этом случае является более быстрое считывание данных.
Таким образом, это может не иметь ничего общего с однопоточностью?
Обезьяна
@ Ape-inago Конечно, хорошо написанное однопоточное приложение может поддерживать полный канал, да.
Spiff
2
Ну, это, вероятно, потому что вы можете передавать столько данных только через одно соединение. Однако в многопоточной программе вы можете иметь два соединения, которые получают данные одновременно и удваивают объем информации, которую вы можете получить. Есть некоторые ограничения в этом, например, скорость сервера, с которого вы скачиваете ... Снимаю шляпу у двух, кто написал многопоточный загрузчик, это нелегко написать.
Почему это так сложно? Вам просто нужно выделить отдельный раздел для каждого потока и позволить ему записать в соответствующий раздел файла результатов. Источник акселя кажется мне довольно простым.
Ответы:
Обычно это происходит потому, что где-то между вами и другим сервером существует брандмауэр, ограничивающий каждый поток HTTP до 10 Мбит / с. Когда вы используете многопоточность, вы получаете 2x 10Mb (по одному для каждой нити).
источник
Это связано с вашим пингом между вами и сервером и размером окна / размера окна tcpip, используемого вашей загружаемой программой.
По сути, если у вас 100 мс на сервер и вы запрашиваете пакеты размером 100 Кб, вы можете получать только 10 пакетов в секунду, используя 1 соединение, даже если ваша скорость интернета бесконечна.
источник
TCP работает лучше всего, когда вы «держите канал заполненным» - когда отправляющее приложение продолжает посылать буферы достаточно быстро, чтобы стек TCP отправителя постоянно получал данные, так что он всегда мог иметь данные «в полете» в сети, и когда получатель приложение продолжает читать из получающего TCP-стека достаточно быстро, чтобы окно TCP получателя никогда не заполнялось (опять же, поэтому отправляющий TCP-стек всегда может сохранять данные «в полете» в сети).
Я мог бы представить плохо написанное однопоточное приложение отправителя, которое передает один буфер в стек TCP, ждет, когда он полностью Acked, а затем передает другой буфер. Это означает, что как только конец первого буфера «в полете» в сети, отправляющему стеку TCP не хватает данных для отправки, что означает, что канал истощается и не заполняется до тех пор, пока не вернется Ack и приложение-отправитель. передает ему новый буфер.
Я мог бы также представить плохо написанное однопоточное приложение-получатель, которое недостаточно быстро читает из принимающего TCP-стека и, таким образом, позволяет заполнять буферы TCP-стека, что означает, что окно TCP заполняется, что приводит к тому, что отправляющий TCP-стек прекратить отправку, пока не откроется окно. Увеличение размера окна TCP получателя может немного помочь, но реальным решением в этом случае является более быстрое считывание данных.
источник
Ну, это, вероятно, потому что вы можете передавать столько данных только через одно соединение. Однако в многопоточной программе вы можете иметь два соединения, которые получают данные одновременно и удваивают объем информации, которую вы можете получить. Есть некоторые ограничения в этом, например, скорость сервера, с которого вы скачиваете ... Снимаю шляпу у двух, кто написал многопоточный загрузчик, это нелегко написать.
источник