2014 dxdy logo

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

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




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4  След.
 
 Re: struct S* x;
Сообщение29.10.2021, 20:19 
Аватара пользователя


28/10/21
99
mihaild в сообщении #1536925 писал(а):
TheRuinedMap в сообщении #1536916 писал(а):
на практике именно эта буферизация как раз таки прекрасно управляется из программы через setvbuf
Но всё-таки по стандарту setvbuf управляет внутренней буфферизацией. Что дальше с выводом делает host - стандарт не говорит.


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

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

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

 Профиль  
                  
 
 Re: struct S* x;
Сообщение29.10.2021, 20:20 
Заслуженный участник
Аватара пользователя


16/07/14
8436
Цюрих
TheRuinedMap в сообщении #1536927 писал(а):
Что выводится??? Как я понял Aritaborian ведет речь именно об исходном варианте от автора вопроса.
Да, я перепутал, о чем речь.

 Профиль  
                  
 
 Re: struct S* x;
Сообщение29.10.2021, 20:29 
Аватара пользователя


11/06/12
10390
стихия.вздох.мюсли
На случай, если кого-то запутал, я говорю о коде из post1536901.html#p1536901.

 Профиль  
                  
 
 Re: struct S* x;
Сообщение30.10.2021, 06:03 


18/09/21
1682
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 
Аватара пользователя


28/10/21
99
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 


18/09/21
1682
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 
Аватара пользователя


28/10/21
99
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 


18/09/21
1682
TheRuinedMap в сообщении #1536976 писал(а):
Зачем?
Вот попробуйте и посмотрите на время. Разница в буферизации между "\n" и 'std::endl' налицо.

 Профиль  
                  
 
 Re: struct S* x;
Сообщение30.10.2021, 06:51 
Аватара пользователя


28/10/21
99
zykov в сообщении #1536977 писал(а):
TheRuinedMap в сообщении #1536976 писал(а):
Зачем?
Вот попробуйте и посмотрите на время. Разница в буферизации между "\n" и 'std::endl' налицо.


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

 Профиль  
                  
 
 Re: struct S* x;
Сообщение30.10.2021, 07:43 


18/09/21
1682
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 
Аватара пользователя


28/10/21
99
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 
Заслуженный участник


20/08/14
11136
Россия, Москва
TheRuinedMap
Разве ОС не изолирует выход потока от программы?! Мне всегда казалось что это дело ОС куда он направлен и программе об этом не узнать и isatty() всегда будет одинаков куда бы ОС не направила поток. А нужен isatty() для различения куда вы сами в программе подсоединили дескриптор. Что потом там с ним дальше вытворит ОС программа не узнает.

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

 Профиль  
                  
 
 Re: struct S* x;
Сообщение30.10.2021, 08:25 


18/09/21
1682
TheRuinedMap в сообщении #1536981 писал(а):
это все - наведенные эффекты
Нет, это фундаментальные эффекты.
Мораль тут простая: хочешь, чтобы наверняка сработал вывод текста (а не так что, тут работает, а тут нет), используй 'flush', пусть даже и в виде 'std::endl', который содержит в себе такой 'flush'.
Но слишком часто и без дела использовать 'std::endl' тоже не стоит, т.к. это может дать проблемы с производительностью.

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

 Профиль  
                  
 
 Re: struct S* x;
Сообщение30.10.2021, 08:31 
Аватара пользователя


28/10/21
99
Dmitriy40 в сообщении #1536983 писал(а):
TheRuinedMap
Разве ОС не изолирует выход потока от программы?! Мне всегда казалось что это дело ОС куда он направлен и программе об этом не узнать и isatty() всегда будет одинаков куда бы ОС не направила поток. А нужен isatty() для различения куда вы сами в программе подсоединили дескриптор.


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

 Профиль  
                  
 
 Re: struct S* x;
Сообщение30.10.2021, 08:40 
Заслуженный участник


20/08/14
11136
Россия, Москва
TheRuinedMap в сообщении #1536985 писал(а):
Нет, не изолирует. Попробуйте сами: обычный вывод в консоль дает единицу из isatty(1), перенаправленный вывод дает ноль.
Очень странно на мой взгляд.

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

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 53 ]  На страницу Пред.  1, 2, 3, 4  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group