non-blocking-io vs blocking-io для пропускной способности необработанных данных - PullRequest
8 голосов
/ 11 января 2012

В apache HTTPComponent document есть утверждение:

Вопреки распространенному мнению, производительность NIO с точки зрения пропускной способности необработанных данных значительно ниже, чем у блокировкиI / O. "

Это правда? Может кто-нибудь объяснить это более подробно? И каков типичный случай использования, когда

обработка запроса / ответа должна бытьразвязанный

Ответы [ 2 ]

3 голосов
/ 09 февраля 2012

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

Но вернемся к вашему вопросу. Почему NIO может быть медленнее с точки зрения пропускной способности необработанных данных? Причина - количество процессорного времени, используемого приложениями, управляемыми NIO. Для такого случая в модели блокировки ваш код выполняет только одно - ожидание данных (он выполняет операцию recv () в цикле). В приложении NIO логика гораздо сложнее: в цикле код использует селектор для выбора набора ключей (который включает системный вызов epoll_wait в Linux, Oracle JVM), затем итерацию по набору, выбор канала для каждый ключ, а затем прочитать данные из канала (операция чтения () в ОС). В стандартной модели блокировки все, что вы делаете, это выполняете системную функцию recv (). Итак, приложение, управляемое NIO, в этом случае использует больше процессорного времени и генерирует больше операций переключения режимов из-за большого количества системных вызовов (говоря, что переключение режима означает переход от режима пользователя к режиму ядра). Поэтому время, необходимое для загрузки файла, будет выше.

3 голосов
/ 09 февраля 2012

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

Я бы рекомендовал прочитать netty документацию для лучшего понимания концепции.

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

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

...