Причины медленного вызова - PullRequest
3 голосов
/ 13 декабря 2010

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

Я всегда отправляю заголовок размером 64 байта, который содержитдлина следующего тела сообщения и некоторая другая информация.

При тестировании моего приложения на некоторых файлах я обнаружил, что некоторые вызовы recv выполняются довольно долго (около 40 мс ).Используя strace, я обнаружил, что это происходит в первую очередь при отправке тела сообщения размером 377 байт (что в данном случае копирует весь контент моего файла).

Серверное приложение начинает отправку тела сообщения, что занимает около 48 us .Теперь клиентское приложение потребляет около 38 мс для получения этих байтов.

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

серверный режим

[pid 27158] 1292236124.465827 отправить (6, "\ 0 \ 0 \ 1 \ 271 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0core.fwrite \ 0 \ 0 \ 0 \ 0 \ 0 \ 0\ 0 \ 0 \ 0 "..., 64, 0) = 64 <0,000031>

[pid 27158] 1292236124.466074 отправить (6," \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0\ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 10 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0"..., 377, 0) = 377 <0,000048>

клиентский номер

[pid 27159] 1292236124.466364 recv (4," \ 0 \ 0 \ 1\ 271 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0core.fwrite \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 "..., 64, 0) = 64 <0.000027>

[pid 27159] 1292236124.466597 recv (4, "\ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 10\ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 1 \ 0 \ 0 \ 0 \ 0 "..., 377, 0) = 377 <0,037456>

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

Любые советы будут высоко оценены.

Ответы [ 2 ]

7 голосов
/ 13 декабря 2010

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

0 голосов
/ 13 декабря 2010

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

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

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

Даже при такомСтратегия все еще может стоить отключить алгоритм Nagle.Если не считать чего-либо, если ваш код разработан так, чтобы избежать множества маленьких пакетов, алгоритм Nagle является избыточным.

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