fprintf && write
- From
- Andrey Melnikov (2:5030/1340.116)
- To
- Boris Rudakov ()
- Date
- 2003-06-04T13:18:10Z
- Area
- CARBON.COPY
* Forwarded from area 'RU.UNIX.PROG'
Hello Boris!
04 Jun 03 10:57, Boris Rudakov wrote to Andrey Melnikov:
AM>> Что-то у меня лыжи не едут совсем.
BR> Я по специализации не юниксоид, поэтому изначально в тред не встревал. Но
BR> у тебя в тексте есть несколько ляпов, на которые я хотел бы обратить
BR> внимание вчисле прочего уже сказанного :)
Ляпы я уже поправил. ;)
BR> Часть замечаний совсем "общего плана", не касаемо заданного вопроса.
AM>> Беру софтину, которая всю свою разумную жизнь работала так:
AM>> out = fdopen(out_fd, "w");
AM>> ....
AM>> fprintf(out, "%s", buffer);
BR> Не вижу ни малейшего смысла в подобных конструкциях. Кишки xrintfxxx
BR> заняты тем, что интерпретируют единственный "%s" и тупо перекачивают
BR> buffer в out. Накладные расходы в этой и подобных конструкциях
BR> несущественны, но... Зачем они когда можно и без них ?
Я от них и избавлялся.
BR> Я в таких случаях пишу данные непосредственно туду куда нужно,
BR> избегая лишних переписываний во внутренних буфферах.
BR> Чен'ть типа write(out, .....);
AM>> ....
AM>> Выкидываю все эти fprintf() и заменяю на свою функцию:
AM>> static char wr_buf[1024];
BR> Для теста - прокатит, а вообще стоит избегать глобальных переменных. Я
BR> нахожу что весь код нужно писать реентерабельным. Если нет ОСОБЫХ причин
BR> делать иначе :) Я бы этот буфер увеличил раза в 4 и засунул внутрь функции
BR> :)
Дороже выйдет. Войти в процедуру, отрезать кусок стека. Выйти - подчистить. Код у меня не реентрабельный - задача того не требует.
AM>> write_out (int fd, char *fmt, ...){
[куча глюко-кода skipp]
AM>> return 0;
AM>> }
AM>> И скорость падает в 2 (два) с лишним раза. Где я тут неправ ?
BR> Если рассудить логически, то:
BR> 1. write - синхронный блокирующий вызов (или я не прав ?). Но, как бы то
BR> ни было, ты скармливаешь ему весь буффер. Если бы он у тебя выводил не
BR> весь буффер, а часть - ты бы давно уже заметил что твой код неправилен и
BR> поправил бы приращение буфера и декремент длины. Значит - write у тебя
BR> пишет все одним махом. Значит - глюк не в нем.
Не в нем. Прверено экспереметально.
BR> 2. Кроме write у тебя есть только один вызов API - select (в Виндах я бы
BR> сказал "Вызов функции ядра", но думаю что и тут с select этот термин будет
BR> точен). Морал - тормозит (сверх ожидаемого) он.
Наверное - слово тормозит здесь не самое уместное. Я бы сказал - чаще делиться временем со всеми остальными задачами. Или я неправ ?
BR> Моя теория такова (еще раз шаркну ножкой что я не юниксоид, но основные
BR> принципы едины):
BR> * Твой код делает два системных вызова.
Да. Но без них - у меня два варианта:
1. Получить засыпание при вызове fprintf(...) где-то в ядре на write(..) на очень большое время, что увы неприемлимо.
2. Использовать alarm(time), write()/fprintf(), alarm(0); - я получу 3 системных вызова.
BR> * Твой код выводит все за одну итерацию (иначе ты бы уже заметил ошибки в
BR> нем).
Я их в нем заметил. Но из фидо сложно заканселить уже ушедшее письмо :)
BR> Итого - ты делаешь ровно один select и ровно один write.
Да, именно так.
BR> * "Меня терзают смутные сомнения" что fprintf же делает только один -
BR> синхроный блокирующий write. И делает только один write (правда х.з. что
BR> он делает при переполнении внутренних буфферов при форматировании строки -
BR> может быть он делает серию write по мере их заполнения; однако, думаю что
BR> в твоем случае ему там хватает одного write).
Наверное - во внутренностях glibc можно сломать все ноги.
BR> * Так же меня "терзают смутные сомнения" что select - дорогой вызов,
BR> дороже write.
BR> Таким образом, сдается мне что двукратное замедление вызвано тем, что ты в
BR> два раза чаще беспокоишь ядро системы :)
А вот такой вот я плохой - забочусь об состоянии endpoint'a...
Andrey aka TEMHOTA-RIPN
--- GoldED+/LNX 1.1.4.7
* Origin: Powered by SlackWare Linux (2:5030/1340.116)