LINUX.ORG.RU

[holy war] stdio.h vs iostream


0

0

Навеяло одной из предыдущих веток. Действительно ли есть существенные различия в производительности stdio и iostream?? Это общепризнанно или как? Для меня рушится целый мир.

anonymous

> Навеяло одной из предыдущих веток. Действительно ли есть существенные различия в производительности stdio и iostream?? Это общепризнанно или как? Для меня рушится целый мир.

Да, есть. iostream "искаропки" помедленнее.

Хотя там вроде можно буфер побольше установить... Или я неправ?

gaa ★★
()
Ответ на: комментарий от klalafuda

> блин ну напишите тест на сто строк да измерьте

$ cat test_io.c
#include <stdio.h>

int main()
{
  int i;
  for (i=100000000; i--; )
  {
    printf("%s", "some not very long line\n");
  }
  return 0;
}

$ gcc -O3 test_io.c
$ time ./a.out > /dev/null

real    0m5.294s
user    0m5.244s
sys     0m0.052s
$ ls -s a.out
8 a.out

$ cat test_io.cpp
#include <iostream>

int main()
{
  int i;
  for (i=100000000; i--; )
  {
    std::cout << "some not very long line\n";
  }
  return 0;
}

$ g++ -O3 test_io.cpp
$ time ./a.out > /dev/null

real    0m7.101s
user    0m7.052s
sys     0m0.048s
$ ls -s a.out
8 a.out

dilmah ★★★★★
()

>Для меня рушится целый мир.

Скажи еще что тебе нравится архитектура <iostream> и ты в ней полноситью разобрался. В Жабе например InputStream - это простой как пробка абстрактный класс с дюжиной виртуальных методов. Можно in-place завраппить в InputStream любой массив или сокет и передать куда угодно. И будет работать как часы. Для сравнения можно попытаться завраппить TCP сокет в std::istream.

Absurd ★★★
()
Ответ на: комментарий от dilmah

2dilmah:

Не совсем корректный тест.

Если сделать навороченную форматную линию, то printf сильно сольет форматированию потоковыми манипуляторами. По крайней мере, лет 5 назад на ГЦЦ было так. Там все форматирование на парзингом форматной строки делалось, а в компайлтайм инлайнилось.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

> Если сделать навороченную форматную линию, то printf сильно сольет форматированию потоковыми манипуляторами.

Надо же, наоборот!

В 2001 году спорили тут, что быстрее -- потоки с манипуляторами тогда выиграли. Сейчас простой тест прогнал:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
  int i;
  for (i=10000000; i--; )
  {
   std::cout << fixed << setprecision(3) << 1.0 <<' '<<                                   
   setprecision(5)<< 2.0 
   <<' '<< setprecision(6)<<3.0<<' ' 
   << setprecision(7)<<4.0 << endl;
  }
  return 0;
}

-- сливает printf("%.3f %.5 %.6 %.7\n", 1.0,2.0,3.0,4.0); 
в разы (в смысле, printf быстрее)...

Die-Hard ★★★★★
()
Ответ на: комментарий от alex_custov

>не знаю как TCP, но COM порт нормально заврапили (libserial)

Ну и как его передавать клиенту кода - по ссылке sdt::iostream& чтоли ? А кто будет хостить объект в таком случае?

Absurd ★★★
()
Ответ на: комментарий от Absurd

Re^2: [holy war] stdio.h vs iostream

> Для сравнения можно попытаться завраппить TCP сокет в std::istream.

Уже давно заврапили. socket++ называется.

P.S. Завязывай с плюсплюсоненавистничеством, если главный аргумент "в жабе красивее".

gaa ★★
()
Ответ на: Re^2: [holy war] stdio.h vs iostream от gaa

>Завязывай с плюсплюсоненавистничеством, если главный аргумент "в жабе красивее".

Это не вопрос красивости, это *важно*. Стрим должен выглядеть так:

class BasicInputStream {
public:
virtual std::size_t read(unsigned char *buff, std::size_t offset, std::size_t len) = 0;
virtual boolean eof() = 0;
virtual void close() = 0;
};

Так пользователю надо определить только три функции. Такие стримы можно элементарно нанизывать друг на друга - буфферизация, ssl, сеть etc.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Re^4: [holy war] stdio.h vs iostream

> Стрим должен выглядеть так:

Не надо обобщать свои критерии важности на всех.

> Так пользователю надо определить только три функции. Такие стримы можно элементарно нанизывать друг на друга - буферизация, ssl, сеть etc.

iostream-овские тоже нанизывают. Не вижу никаких преимуществ жабного метода.

gaa ★★
()
Ответ на: комментарий от Absurd

вот чтение из COM порта:

char next_byte;

while(serial_port.rdbuf()->in_avail() > 0)
{
    serial_port.get(next_byte);
    // save next_byte somewhere...
}

Всё стандартное. Сам SerialStream унаследован от std::iostream.

alex_custov ★★★★★
()
Ответ на: Re^4: [holy war] stdio.h vs iostream от gaa

>> Так пользователю надо определить только три функции. Такие стримы можно элементарно нанизывать друг на друга - буферизация, ssl, сеть etc.

>iostream-овские тоже нанизывают.

А какая там политика владения в этой топологии объектов? Семантику значений надо делать чтобы аггрегировать один стрим в другой или по указателю?

>Не вижу никаких преимуществ жабного метода.

Это не только жабный метод - я привел скорее COM-овский код.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Re^6: [holy war] stdio.h vs iostream

> А какая там политика владения в этой топологии объектов? Семантику значений надо делать чтобы аггрегировать один стрим в другой или по указателю?

Дядь, ты с кем сейчас разговаривал? Растолкуй для тупых математиков.

gaa ★★
()
Ответ на: комментарий от alex_custov

Re^4: [holy war] stdio.h vs iostream

> while(serial_port.rdbuf()->in_avail() > 0)

А что ж не while(serial_port.ok()) ?

gaa ★★
()
Ответ на: Re^6: [holy war] stdio.h vs iostream от gaa

>Дядь, ты с кем сейчас разговаривал? Растолкуй для тупых математиков. 

class BufferedInputStream : public BasicInputStream {
   std::auto_ptr<BasicInputStream> _stream;
   unsigned char* _buffer;
public:
   BufferedInputStream(std::auto_ptr<BasicInputStream> stream, std::size_t bufferSize);
/// Implemented virtual methods
  
};

BufferedInputStream::BufferedInputStream(std::auto_ptr<BasicInputStream> stream, std::size_t bufferSize)
  :_stream(stream), _buffer(::operator new[](bufferSize))
{}

/// Buffering logic

Надеюсь более - менее понятен принцип по которому один такой стрим аггрегируется в другой. И ясен принцип по которому один стрим владеет другим.

Absurd ★★★
()
Ответ на: комментарий от alex_custov

>Всё стандартное. Сам SerialStream унаследован от std::iostream.

Мой интерфейс занимает ~200 байт. <iostream> суммарно со всеми вложенностями занимает 400 кб.
И при этом функционал в общем такой же - ведь единственный вменяемый способ чего-то прочитать из std::istream это сделать

std::string userInput;
std::getline(userInput, std::cin);
// parse userInput using regexps or someting like lex/yacc....

Следовательно 400 Кб всех эти бесконечных специализаций оператора >> бесполезны и нахрен не нужны. 

Absurd ★★★
()
Ответ на: комментарий от Absurd

Кстати, я недавно с товарищем спорил на эту же тему. Он большой любитель istream. Доводы приводил такие же как и ты - не помогло. Думаю и тут не поможет. Просто забей. У людей стереотипы java-плохо.

Ian ★★
()
Ответ на: комментарий от Absurd

Re^8: [holy war] stdio.h vs iostream

> BufferedInputStream(std::auto_ptr<BasicInputStream> stream, std::size_t bufferSize);

Я бы назвал такое половым извращением. Уже за auto_ptr.

> Надеюсь более - менее понятен принцип по которому один такой стрим аггрегируется в другой. И ясен принцип по которому один стрим владеет другим.

Не увидел проблемы. Да, за временем жизни переменной надо следить, но это надо делать везде, а не только в iostream.

gaa ★★
()
Ответ на: комментарий от Absurd

Re^4: [holy war] stdio.h vs iostream

> И при этом функционал в общем такой же - ведь единственный вменяемый способ чего-то прочитать из std::istream это сделать std::getline(userInput, std::cin);

Tensor<2,3,double> t;

cin >> t;

Перепиши это "вменяемым" способом а потом задумайся, насколько получилось вменяемо и читабельно :)

> Следовательно 400 Кб всех эти бесконечных специализаций оператора >> бесполезны и нахрен не нужны.

Не умеешь пользоваться -- не говори, что они не нужны.

gaa ★★
()
Ответ на: Re^8: [holy war] stdio.h vs iostream от gaa

>Я бы назвал такое половым извращением. Уже за auto_ptr.

auto_ptr - часть C++ std lib. Или в какой-то новой книжке по С++ его объявили "злом"?.

>Не увидел проблемы. Да, за временем жизни переменной надо следить, но это надо делать везде, а не только в iostream.

Проблема в том что весь <iostream> - это индусокод. Интерфейс должен быть необходимым и достаточным. Стрим в частности должен читать чанки байт и ничего более. Интерпретировать информацию должны парсеры навешивающиеся сверху на стрим.

Absurd ★★★
()
Ответ на: комментарий от Absurd

>>Мой интерфейс занимает ~200 байт

А хуле толку от этих 200 байт, когда любой класс, реализующий этот интерфейс, превратится в конце концов в копию iostream'a ? Подсчёт количества переданных байт, флаги ошибок, расположения указателя внутри потока, и прочее прочее прочее... Всё это будешь навешивать на каждую конкретную реализацию? (Только не говори что это не нужно)

alex_custov ★★★★★
()
Ответ на: Re^4: [holy war] stdio.h vs iostream от gaa

>Tensor<2,3,double> t; >cin >> t; >Перепиши это "вменяемым" способом а потом задумайся, насколько получилось вменяемо и читабельно :)

Tensor<2,3,double> t; readTensor(t, std::cin);

>> Следовательно 400 Кб всех эти бесконечных специализаций оператора >> бесполезны и нахрен не нужны.

>Не умеешь пользоваться -- не говори, что они не нужны.

Хорошо, так: 1) Зачем они нужны когда есть регулярные выражения и yacc ? 2) Зачем мне инклюдить 400 Кб говна из <iostream>, когда мне надо просто тупо читать чанки бинарных данных с внешнего устройиства?

Absurd ★★★
()
Ответ на: комментарий от alex_custov

>>Мой интерфейс занимает ~200 байт

>А хуле толку от этих 200 байт, когда любой класс, реализующий этот интерфейс, превратится в конце концов в копию iostream'a ?

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

Absurd ★★★
()
Ответ на: комментарий от Absurd

то что ты привёл - это примитив на уровне 1-го курса. Из разряда задач по "базам данных" в текстовых файлах. Если тебе нужна такая примитивщина, никто не запрещает сделать свои 200-байтные интерфейсы и пользоваться. Кому нужен функционал - те пользуют что-то более вменяемое (iostream).

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

>то что ты привёл - это примитив на уровне 1-го курса.

Это интерфейс типа COM-овского IStream. Он удовлетворяет критериям "необходимости" и "достаточности". Кому надо парсить сложный ввод навесят сами на него нужный функционал, который вероятно идет в той же библиотеке в других заголовочных файлах.

>Кому нужен функционал - те пользуют что-то более вменяемое (iostream).

Нет, iostream невменяем. Лучше тогда уж использовать <stdio.h>.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Re^6: [holy war] stdio.h vs iostream

> readTensor(t, std::cin);

Отлично. Теперь напиши ещё readInt, readDouble, readString и т.д. И увидишь всё те же 400 кб "говна", только в профиль :)

> Хорошо, так: 1) Зачем они нужны когда есть регулярные выражения и yacc?

Зачем нужна вилка, когда есть ложка?

> 2) Зачем мне инклюдить 400 Кб говна из <iostream>, когда мне надо просто тупо читать чанки бинарных данных с внешнего устройиства?

Тебя под страхом смерти заставляют использовать iostream для этой задачи?

gaa ★★
()
Ответ на: комментарий от Absurd

Re^4: [holy war] stdio.h vs iostream

> Нет, iostream невменяем. Лучше тогда уж использовать <stdio.h>.

Никаких других аргументов, кроме Вашего субъективного неприятия iostream Вы так и не предоставили.

gaa ★★
()
Ответ на: Re^6: [holy war] stdio.h vs iostream от gaa

>Теперь напиши ещё readInt, readDouble, readString и т.д. И увидишь всё те же 400 кб "говна", только в профиль :)

Во-первых функция readInt будет работать через getline + регулярное выражение, следовательно оно не будет оставлять стрим в непонятном состоянии после того как пользователь ввел "13BoZo". Во вторых, там надо будет сделать диагностику парсинга чтобы выдать вменяемое сообщение об ошибке. В третьих, если ввод осуществляется с tty неплохо бы дать возможность попробовать еще раз. Ну и в четвертых 400 Кб там не будет, поскольку парсинг текстовых данных никакого отношения к стримам не имеет, следовательно он будет помещен в отдельный модуль.

>> Хорошо, так: 1) Зачем они нужны когда есть регулярные выражения и yacc?

>Зачем нужна вилка, когда есть ложка?

Размером pcre AFAIK намного меньше половины мегабайта (размер iostream), и работает в разы надежней. И в разы гибче.

>> 2) Зачем мне инклюдить 400 Кб говна из <iostream>, когда мне надо просто тупо читать чанки бинарных данных с внешнего устройиства?

>Тебя под страхом смерти заставляют использовать iostream для этой задачи?

Типичное сиплюсплюсное виляние. Например в твоей любимой Java есть пакет java.nio для асинхронного блочного ввода-вывода c использованием буферов фиксированного размера. На Линуксе оно реализовано через epoll(). Есть выбор какой-то блин.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Re^8: [holy war] stdio.h vs iostream

Предлагаю ещё пофантазировать на тему: распарсить одним разом матрицу в формате "высота ширина\nстрока 1\nстрока 2\n...строка n". Одной функцией. Сколько там данных потребуется прочитать?

> Размером pcre AFAIK намного меньше половины мегабайта (размер iostream), и работает в разы надежней. И в разы гибче.

Угу, значит уже часть stl работает ненадёжно... Кстати, pcre -- не часть плюсового стандарта, а только часть posix-а. Но явисты, конечно, знают, что должно быть в стандарте цпп :)

gaa ★★
()
Ответ на: Re^8: [holy war] stdio.h vs iostream от gaa

>Кстати, pcre -- не часть плюсового стандарта, а только часть posix-а

Т.н. плюсовый стандарт - интересная вещь. Он неявно подразумевает что на машине есть 32-битовая виртуальная память, но при этом считает что на машине нету curses/ncurses.

>Но явисты, конечно, знают, что должно быть в стандарте цпп :)

Я на яве пишу конечно, но не только на ней.

Absurd ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.