Что быстрее: многократная посылка или использование буферизации? - PullRequest
5 голосов
/ 14 апреля 2010

Я играю с сокетами в C / Python, и мне интересно, как наиболее эффективно отправить заголовки из словаря Python в клиентский сокет.

Мои идеи:

  1. используйте send вызов для каждого заголовка. Плюсы : выделение памяти не требуется. Минусы : много вызовов send - возможно, подвержены ошибкам; Управление ошибками должно быть довольно сложным
  2. использовать буфер. Плюсы : один send вызов, проверка ошибок намного проще. Минусы : нужен буфер :-) malloc / realloc должен быть довольно медленным и использовать (слишком) большой буфер, чтобы избежать realloc вызовов, тратящих память.

Какие-нибудь советы для меня? Спасибо: -)

Ответы [ 3 ]

3 голосов
/ 14 апреля 2010

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

Если у вас есть только несколько небольших заголовков, и ваши вызовы на send выполняются быстро, операционная система обычно буферизует данные для вас и отправляет их все в одном пакете. В этом случае контроль перегрузки TCP не является проблемой. Однако каждый вызов send включает переключение контекста из пользовательского режима в режим ядра, что приводит к перегрузке ЦП. Другими словами, вам все равно лучше буферизовать в своем приложении.

Есть (по крайней мере) один случай, когда вам лучше без буферизации: когда ваш буфер медленнее, чем издержки переключения контекста. Если вы пишете сложный буфер в Python, это вполне может иметь место. Буфер, написанный на CPython, будет немного медленнее, чем точно оптимизированный буфер в ядре. Вполне возможно, что буферизация обойдется вам дороже, чем купит.

Если сомневаешься, измерить.

Одно слово предостережения: преждевременная оптимизация - корень всего зла. Разница в эффективности здесь довольно мала. Если вы еще не установили, что это узкое место для вашего приложения, сделайте все, что облегчит вашу жизнь. Вы всегда можете изменить это позже.

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

A send() вызов подразумевает обратную передачу в ядро ​​(часть ОС, которая напрямую связана с аппаратным обеспечением). Он имеет удельную стоимость около нескольких сотен тактов. Это безвредно, если вы не пытаетесь звонить send() миллионы раз.

Обычно буферизация - это вызов send() только один раз, когда «достаточно данных» собрано. «Достаточно» означает не «все сообщение», а что-то вроде «достаточно байтов, так что стоимость за единицу обхода ядра будет меньше». Как правило, буфер объемом 8 кБ (8192 байта) традиционно считается хорошим.

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

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

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

...