2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3, 4  След.
 
 Re: struct S* x;
Сообщение29.10.2021, 20:19 
Аватара пользователя
mihaild в сообщении #1536925 писал(а):
TheRuinedMap в сообщении #1536916 писал(а):
на практике именно эта буферизация как раз таки прекрасно управляется из программы через setvbuf
Но всё-таки по стандарту setvbuf управляет внутренней буфферизацией. Что дальше с выводом делает host - стандарт не говорит.


Да, согласен.

Я раньше интуитивно полагал, что setvbuf управляет неким буфером, реализованным на уровне библиотеки для ввода-вывод через FILE *, а терминал использует свой буфер, ничего не знающий о setvbuf. (В принципе, тут можно найти место и для третьего уровня буферизации между этими двумя.)

Но практические эксперименты как-будто показывают, что либо в традиционных реализациях это один и тот же буфер, либо все эти буферы как-то управляются синхронно.

 
 
 
 Re: struct S* x;
Сообщение29.10.2021, 20:20 
Аватара пользователя
TheRuinedMap в сообщении #1536927 писал(а):
Что выводится??? Как я понял Aritaborian ведет речь именно об исходном варианте от автора вопроса.
Да, я перепутал, о чем речь.

 
 
 
 Re: struct S* x;
Сообщение29.10.2021, 20:29 
Аватара пользователя
На случай, если кого-то запутал, я говорю о коде из post1536901.html#p1536901.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 06:03 
TheRuinedMap в сообщении #1536910 писал(а):
А если ближе к реальной жизни: вывод в терминал обычно буферизуется построчно, из чего все и следует.
Тут Вы заблуждаетесь. Символ перевода строки - такой же символ, как и другие. Он никак не влияет на буферизацию.
Это Вы наверно спутали перевод строки с 'std::endl'. Он действительно в себя включает 'flush'.
Вот вариант одни (никакого сброса буфера):
Используется синтаксис C++
std::cout << "xyz\n";

Вот вариант два (здесь буфер сбрасывается):
Используется синтаксис C++
std::cout << "xyz" << std::endl;


Так что если выводите много текста, то лучше использовать первый вариант - быстрее будет.
А второй вариант (или просто '<< std::flush' если не нужно перерводить строку) я использую, когда хочу отобразить прогресс долгих вычислений.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 06:21 
Аватара пользователя
zykov в сообщении #1536970 писал(а):
TheRuinedMap в сообщении #1536910 писал(а):
А если ближе к реальной жизни: вывод в терминал обычно буферизуется построчно, из чего все и следует.
Тут Вы заблуждаетесь. Символ перевода строки - такой же символ, как и другие. Он никак не влияет на буферизацию.
Это Вы наверно спутали перевод строки с 'std::endl'. Он действительно в себя включает 'flush'.


Ну, тут справедливости ради надо заметить, что все еще зависит и от поведения std::cout. Он, как я понимаю, может привнести свой уровень буферизации со своим поведением. Я в данном случае веду речь о поведении POSIX терминала, потока stdout и надстроенного над ним std::cout в типичных для POSIX реализациях.

И нет, совершенно не верно. Я ни в чем не заблуждаюсь и ни с каким std::endl я ничего не спутал. Режим построчной буферизации - один из натуральных стандартных режимов буферизации, представленных в том числе стандартной константой _IOLBF для функции setvbuf. Именно в таком режиме по умолчанию работают терминалы POSIX и этот режим распространяется и на поведение потока std::cout в стандартной библиотеке GNU. Символ перевода строки НЕ является "обычным символом", а имеет особый смысл, приводящий к выталкиванию накопленного буфера в этом режиме буферизации.

zykov в сообщении #1536970 писал(а):
Вот вариант одни (никакого сброса буфера):
Используется синтаксис C++
std::cout << "xyz\n";


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

zykov в сообщении #1536970 писал(а):
Так что если выводите много текста, то лучше использовать первый вариант - быстрее будет.


Вы, очевидно, перепутали вывод в консоль, который обычно буферизуется в режиме _IOLBF, с выводом в файл, который обычно буферизуется в режиме _IOFBF. При выводе в файл перевод строки действительно не имеет никакого особого статуса. Но здесь мы ведем речь о выводе именно в консоль.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 06:37 
TheRuinedMap в сообщении #1536972 писал(а):
Откуда вы взяли ваше "никакого сброса буфера" - я не знаю.
Из практики.
Как я выше писал, иногда надо отобразить прогресс долгих вычислений (сколько сделано - 10%, 80%?).
Без явного flush (хотя бы в форме endl) прогресс не отображается. Т.е. строка с кодом вывода отработала, вычисления пошли дальше, а текст сидит в буфере и его не видно.

Да, системы бываю разные. Может где под DOS оно и сбрасывало буфер по концу строки - не знаю.
Вот попробуйте под Linux собрать:
Используется синтаксис C++
#include <iostream>

int main() {
    for(int i=0; i < 10000000; i++)
        std::cout << "123456789\n";
}

и
Используется синтаксис C++
#include <iostream>

int main() {
    for(int i=0; i < 10000000; i++)
        std::cout << "123456789" << std::endl;
}

Собрать это как 'g++ tst.cpp' и запустить это как 'time ./a.out >res.txt'.
И почувствуйте разницу.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 06:44 
Аватара пользователя
zykov в сообщении #1536975 писал(а):
TheRuinedMap в сообщении #1536972 писал(а):
Вот попробуйте под Linux собрать:
[...]
Собрать это как 'g++ tst.cpp' и запустить это как 'time ./a.out >res.txt'.
И почувствуйте разницу.


Ым... К чему это здесь? Вы мне какое-то сравнение времен выполнения предлагаете. Зачем? Время выполнения в данном вопросе - характеристика косвенная, т.е. способная лишь нагнать ненужного туману. К тому же вы перенаправили вывод в файл?! O_o Вы вообще читали, о чем идет речь? Я по-моему ясно сказал выше, причем повторил несколько раз (!), что речь идет именно о выводе в консоль, а не в файл. Я не люблю, когда мои сообщения читают невнимательно.

Просто попробуйте под Linux элементарный эксперимент по существу:

Используется синтаксис C++
#include <iostream>
#include <cstdlib>

int main(int argc, char* argv[])
{
   std::cout << "Hello World\n";
   while (rand() >= 0) rand();
}
 


Обратите внимание, что цикл намеренно сделан бесконечным. Затем уберите \n и попробуйте еще раз. Все сразу станет достаточно очевидным.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 06:47 
TheRuinedMap в сообщении #1536976 писал(а):
Зачем?
Вот попробуйте и посмотрите на время. Разница в буферизации между "\n" и 'std::endl' налицо.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 06:51 
Аватара пользователя
zykov в сообщении #1536977 писал(а):
TheRuinedMap в сообщении #1536976 писал(а):
Зачем?
Вот попробуйте и посмотрите на время. Разница в буферизации между "\n" и 'std::endl' налицо.


Я уже закрыл эту тему в своем сообщении выше. Ваш эксперимент совершенно "мимо кассы". Никакого отношения к рассматриваемой теме он не имеет даже отдаленно и ничего не демонстрирует. К чему вы его привели и почему вы продолжаете на нем настаивать - совершенно не ясно.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 07:43 
TheRuinedMap в сообщении #1536978 писал(а):
Я уже закрыл эту тему в своем сообщении выше.
Это Вам только кажется.
Кстати, не нужно этот 'rand' городить. Для бесконечного цикла достаточно 'while(true);'.
Да, действительно, при наличии символа "\n" происходит вывод на консоль.

А теперь вот так попробуйте.
Вариант 1:
Используется синтаксис C++
#include <iostream>

int main()
{
   std::cout << "Hello World\n";
   while(true);
}

и вариант 2:
Используется синтаксис C++
#include <iostream>

int main()
{
   std::cout << "Hello World" << std::endl;
   while(true);
}

Соберите как 'g++ tst.cpp' и запустите как './a.out | tee res.txt'.
И опять же почувствуйте разницу.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 07:57 
Аватара пользователя
zykov в сообщении #1536979 писал(а):
TheRuinedMap в сообщении #1536978 писал(а):
Я уже закрыл эту тему в своем сообщении выше.
Это Вам только кажется.
Кстати, не нужно этот 'rand' городить. Для бесконечного цикла достаточно 'while(true);'.


Нет, не достаточно. В языках С и С++ бесконечные циклы допускаются только в том случае, если они имеют наблюдаемое поведение (observable behavior, т.е. ввод-вывод, доступ к volatile объектам, доступ к atomic объектам и т.п). Если у вас в программе есть бесконечный цикл без наблюдаемого поведения, поведение вашей программы не определено.

То есть никакого while(true); ни в С, ни в С++ не допускается.

clang в таких случаях ведет себя весьма смело: он просто выкинет из программы ваш цикл. https://godbolt.org/z/Y3v5ds4v3

Мой while с rand(), честно говоря, не лучше )) Но по крайней мере тот факт, что rand() меняет глобальное состояние, дает надежду на успех. Его clang выкинуть не осмеливается.

Коррекция: возможно я не прав. Вышесказанное относится только к циклам с неконстантным управляющим выражением? Надо разобраться поглубже...
Ага, в С есть эта оговорка про константность управляющего выражения. В С++ такой оговорки нет.

zykov в сообщении #1536979 писал(а):
Да, действительно, при наличии символа "\n" происходит вывод на консоль.


Именно.

zykov в сообщении #1536979 писал(а):
А теперь вот так попробуйте.
Вариант 1:
Используется синтаксис C++
#include <iostream>

int main()
{
   std::cout << "Hello World\n";
   while(true);
}

и вариант 2:
Используется синтаксис C++
#include <iostream>

int main()
{
   std::cout << "Hello World" << std::endl;
   while(true);
}

Соберите как 'g++ tst.cpp' и запустите как './a.out | tee res.txt'.
И опять же почувствуйте разницу.


Это все очень интересно, но как вы сами, наверное, догадываетесь это все - наведенные эффекты, вызванные перенаправлением стандартного выходного потока. Стандартный выходной поток приложения a.out в такой ситуации не связан с консолью и, поэтому, очевидно работает в режиме полной буферизации. Того же эффекта вы достигнете и через ./a.out | cat.

Меня не удивит, если в реализации стандартной библиотеки GCC стоит банальный if, выбирающий режим буферизации на основе анализа результата isatty(1).

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 08:23 
TheRuinedMap
Разве ОС не изолирует выход потока от программы?! Мне всегда казалось что это дело ОС куда он направлен и программе об этом не узнать и isatty() всегда будет одинаков куда бы ОС не направила поток. А нужен isatty() для различения куда вы сами в программе подсоединили дескриптор. Что потом там с ним дальше вытворит ОС программа не узнает.

zykov
Поведение Ваших последних примеров отличается если поток не перенаправлять и оставить в консоль? Мне думается не должно быть разницы, перенаправлять или нет. Хотя при перенаправлении может вмешиваться ещё одна буферизация ...

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 08:25 
TheRuinedMap в сообщении #1536981 писал(а):
это все - наведенные эффекты
Нет, это фундаментальные эффекты.
Мораль тут простая: хочешь, чтобы наверняка сработал вывод текста (а не так что, тут работает, а тут нет), используй 'flush', пусть даже и в виде 'std::endl', который содержит в себе такой 'flush'.
Но слишком часто и без дела использовать 'std::endl' тоже не стоит, т.к. это может дать проблемы с производительностью.

TheRuinedMap в сообщении #1536981 писал(а):
То есть никакого while(true); ни в С, ни в С++ не допускается.
Ссылку можно? Я уже не говорю про то, что оно работает на практике.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 08:31 
Аватара пользователя
Dmitriy40 в сообщении #1536983 писал(а):
TheRuinedMap
Разве ОС не изолирует выход потока от программы?! Мне всегда казалось что это дело ОС куда он направлен и программе об этом не узнать и isatty() всегда будет одинаков куда бы ОС не направила поток. А нужен isatty() для различения куда вы сами в программе подсоединили дескриптор.


Нет, не изолирует. Попробуйте сами: обычный вывод в консоль дает единицу из isatty(1), перенаправленный вывод дает ноль.

 
 
 
 Re: struct S* x;
Сообщение30.10.2021, 08:40 
TheRuinedMap в сообщении #1536985 писал(а):
Нет, не изолирует. Попробуйте сами: обычный вывод в консоль дает единицу из isatty(1), перенаправленный вывод дает ноль.
Очень странно на мой взгляд.

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

 
 
 [ Сообщений: 53 ]  На страницу Пред.  1, 2, 3, 4  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group