Здравствуйте, anatoly1, Вы писали:
A>С++ медленнее питона при парсинге файла.
Грубое использование string, vector, sstream объектов. Время уходит на запросы памяти
в этих контейнерах. По мне так лучше сначала выделить буферы фиксированного размера,
и в процессе использовать их, с контролем переполнения. Эти буферы можно передавать
и в sstream, и в string/vector, которые будут передаваемые им элементы помещать
в эти буферы, не делая постоянные malloc.
А вообще прикольно писать парсеры не тупо на контейнерах, а примерно так:
Здравствуйте, Aртём, Вы писали:
Aё>Здравствуйте, anatoly1, Вы писали:
Aё>>> ====>>>> Copy constructor !!!
A>>Компилятор такое сейчас умеет оптимизировать. Aё>Ссылку?
Здравствуйте, anatoly1, Вы писали:
A>С++ медленнее питона при парсинге файла.
А как на питоне это делается? A>В чём может быть причина такой низкой производительности у С++?
В том, что это у тебя не С++.
Здравствуйте, anatoly1, Вы писали:
A>С++ медленнее питона при парсинге файла.
A>С++ — версия:
A>В чём может быть причина такой низкой производительности у С++?
А что-нибудь меняется, если первой строкой написать std::ios_base::sync_with_stdio(false); ?
Здравствуйте, anatoly1, Вы писали:
A>Здравствуйте, _DAle_, Вы писали:
_DA>>А что-нибудь меняется, если первой строкой написать std::ios_base::sync_with_stdio(false); ?
A>
A>error: expected constructor, destructor, or type conversion before '(' token
A>
Здравствуйте, _DAle_, Вы писали:
_DA>Первой строкой в main()
Я уже чуть выше выкладывал результат в release-режиме (в первом посте, по моей невнимательности, был дебаг-режим).
Результат с опцией std::ios_base::sync_with_stdio(false) получился таким:
Здравствуйте, smeeld, Вы писали:
S>А вообще прикольно писать парсеры не тупо на контейнерах, а примерно так:
<skipped>
А вот так проще. Используем strtok, которая для этого и предназначена. При этом не выделяется ни одного байта памяти. Правда, исходная строка портится, но это не так уж важно.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А вот так проще. Используем strtok, которая для этого и предназначена. При этом не выделяется ни одного байта памяти. Правда, исходная строка портится, но это не так уж важно.
A>В чём может быть причина такой низкой производительности у С++?
В версии на C++ аллоцируется много мутабельных строк, в то время как в версии на Python строки иммутабельные, для них просто берётся view.
Плюс, у тебя vector аллоцируется каждый раз создаётся заново, а нужно создать его только один раз и переиспользовать его capacity многократно.
Здравствуйте, smeeld, Вы писали:
S>Покапитанить решили? Не интересно так.
Интересно или нет, но эту функцию никто здесь не упомянул. Получилось впечатление, что либо нужно писать что-то совсем уж вручную (как у тебя), или без STL никак не обойтись. Вот я и решил напомнить...
ветке сокрушались о бустовской реализация is_any_of. Возможно, что и на текущий день ситуация со производительностью split кардинально не поменялась. Вот в этой
Здравствуйте, anatoly1, Вы писали:
A>С++ медленнее питона при парсинге файла.
A>С++ — версия: A>...
A>А вот питон — версия: A>...
A>В чём может быть причина такой низкой производительности у С++?
Причина в том, что это у вас абсолютно разные коды. Версия на Питоне просто просматривает файл и всё. А версия на C++ ещё и делает некие дополнительные действия — создаёт копии определённых кусков данных из файла. Если вы хотите получить реальную C++ копию кода на Питоне, то это будет что-то вроде:
Здравствуйте, anatoly1, Вы писали:
A>Сделал так: A>
A>std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
A> std::stringstream ss(s);
A> std::string item;
A> for (int i = 0; std::getline(ss, item, delim); i++)
A> elems[i] = std::move(item);
A> return elems;
A>}
A>
Аллоцируются строки для каждого элемента в s, stringstream создаётся каждый раз заново. elems должен содержать просто string view.
Да и вообще, в зависимости от задачи, может и elems не нужен — можно обрабатывать по месту.
Здравствуйте, smeeld, Вы писали:
S>А вообще прикольно писать парсеры не тупо на контейнерах, а примерно так: S>struct parser{
надо создать форум "код по укурке"
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
ветке сокрушались о бустовской реализация is_any_of. Возможно, что и на текущий день ситуация со производительностью split кардинально не поменялась. Вот в этой
Здравствуйте, alex_public, Вы писали:
_>И соответственно этот код работает у меня где-то в 2,5 раза быстрее, чем его аналог на Питоне.
Осталось немного, и придёт, наконец, понимание, что здесь, в этой задачке, контейнеры и стримы вообще
ни куда не упёрлись. Их нельзя использовать на каждый чих. Сформировать malloc-ом буфер с содержимым
файла, разбить его на токены или предложения нуль терминатором, последовательно с занесением указателей в массив.
Вот указатели, а лучше их unique_ptr, можно уже складывать в вектор. Только не забыть задать ему первоначальный
размер отличный от нуля, а то vector, созданный дефолтным конструктором, сначала запрашивает память под объект,
потом под два, копируя туда содержание предыдущего буфера и удаляя его, потом под четыре и так далее, кто-то
скажет, что использовать такой способ организации буфера правильно?
Здравствуйте, smeeld, Вы писали:
S>Осталось немного, и придёт, наконец, понимание, что здесь, в этой задачке, контейнеры и стримы вообще S>ни куда не упёрлись. Их нельзя использовать на каждый чих. Сформировать malloc-ом буфер с содержимым S>файла,
Во-первых он файл уже отмэппил файл в память, без всяких аллокаций. А во-вторых, даже если выделять память под весь файл, malloc от вектора практически ничем не будет отличатся в плане скорости
S>разбить его на токены или предложения нуль терминатором, последовательно с занесением указателей в массив. S>Вот указатели, а лучше их unique_ptr, можно уже складывать в вектор.
Указатели на внутренние элементы массива в unique_ptr?
S>Только не забыть задать ему первоначальный S>размер отличный от нуля, а то vector, созданный дефолтным конструктором, сначала запрашивает память под объект,
Дефолтный конструктор создаёт пустой вектор, и на популярных реализациях с нулевой capacity.
S> потом под два, копируя туда содержание предыдущего буфера и удаляя его, потом под четыре и так далее, кто-то S>скажет, что использовать такой способ организации буфера правильно?
При неизвестном конечном размере — вполне себе, добавление amortized O(1) (в системах подверженных фрагментации памяти, лучше брать factor меньше золотого сечения)
А если размер известен, либо есть "типичное" значение, то тогда просто делается .reserve(x).
EP>Во-первых он файл уже отмэппил файл в память, без всяких аллокаций. А во-вторых, даже если выделять память под весь файл, malloc от вектора практически ничем не будет отличатся в плане скорости
Если не изменяет память, то ТС в vector пихает структуру std::string, std::basic_string::_Alloc_hider::_M_p которой содержит
указатель на кусок памяти с строкой, который аллоцируется, с копированием строки из файла, в строчке std::getline(ss, item, delim))
Так что кроме мапа файла есть ещё куча кусков, разбросанных по просторам виртуальной памяти.
EP>Указатели на внутренние элементы массива в unique_ptr?
Думал не заметите
EP>Дефолтный конструктор создаёт пустой вектор, и на популярных реализациях с нулевой capacity.
Это понятно, беда начинается, когда начинаем пустому vector делать push_back/emplace_back. Вот тут
он начинает наращивать свою capacity, последовательно-куча новых аллокаций на первых элементах.
EP>При неизвестном конечном размере — вполне себе, добавление amortized O(1) (в системах подверженных фрагментации памяти, лучше брать factor меньше золотого сечения) EP>А если размер известен, либо есть "типичное" значение, то тогда просто делается .reserve(x).
Это понятно, только у ТС так не сделано, потому и упомянуто.
Здравствуйте, smeeld, Вы писали:
EP>>Во-первых он файл уже отмэппил файл в память, без всяких аллокаций. А во-вторых, даже если выделять память под весь файл, malloc от вектора практически ничем не будет отличатся в плане скорости S>Если не изменяет память, то ТС в vector пихает структуру std::string, std::basic_string::_Alloc_hider::_M_p которой содержит
Ты же отвечал на сообщение alex_public? А у него mapped_file_source.
EP>>Дефолтный конструктор создаёт пустой вектор, и на популярных реализациях с нулевой capacity. S>Это понятно, беда начинается, когда начинаем пустому vector делать push_back/emplace_back. Вот тут S>он начинает наращивать свою capacity, последовательно-куча новых аллокаций на первых элементах.
Тут основная задача не в том чтобы на каждой итерации была одна аллокация вместо логарифма, а в том чтобы вообще избавится от аллокаций на каждой итерации, т.е. переиспользовать уже имеющуюся capacity. В этом случае от O(log(max_tokens_per_string)) аллокаций на всё приложение не будет никакой беды (хотя конечно reserve не помешает, но не критичен).
EP>Ты же отвечал на сообщение alex_public? А у него mapped_file_source.
У alex_public всё как надо, мене не понятно только одно: зачем
тащить всякое из boost, когда в любой ОС есть нативные средства
маппинга, который boost и врайпит. Мне, года проведшему на чистом
posix API в solaris, не понятно, почему такая мода на библиотеки?
Здравствуйте, smeeld, Вы писали:
S>У alex_public всё как надо, мене не понятно только одно: зачем S>тащить всякое из boost, когда в любой ОС есть нативные средства S>маппинга, который boost и врайпит. Мне, года проведшему на чистом S>posix API в solaris, не понятно, почему такая мода на библиотеки?
1. Кроссплатформенность.
2. Это часть Boost.Iostreams, в которой определен набор концепций-интерфейсов. Соответственно враппер даёт нужный интерфейс, со всеми вытекающими.
3. Идиоматичность — RAII, etc.
Учитывая всё это, мне вот наоборот непонятно зачем кому-то использовать голое API при наличии готовых библиотек, предоставляющих все необходимые возможности.
Однако ж, гонка вооружений по прострелу ноги в C++ впечатляет Жесть какая.
Under the following circumstances, the compilers are permitted to omit the copy- and move-constructors of class objects even if copy/move constructor and the destructor have observable side-effects.
Т.е. ладно бы компилятор был обязан отбросить, но он же не обязан- т.е. поведение программы непредсказуемо отличается между debug и release компиляцией и даже release с разными ключиками.
Только Java и C (без плюсанутых) спасут этот мир .
Распарсить большой файл, каждая строчка которого имеет формат вида:
a1;a2;a3;a4;...;a200
Необходимо каждую такую строку преобразовать в объект наподобие:
obj = ["a1", "a2", ..., "a200"]
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>непонятно зачем кому-то использовать голое API при наличии готовых библиотек, предоставляющих все необходимые возможности.
зачем с++ ???
код похож на каку, платят за весь тот объём знаний, ухищрений, наработок и костылей мало,
есть же нормальные ФЯ, в которых не нужно задумываться о каком-то токенайзере,
в которых можно строить всевозможные типы данных, хитросплетения функций,
в которых всё легко запараллеливается, кода мало и он красивый
Здравствуйте, anatoly1, Вы писали:
Ф>>как я могу повторить ваш эксперимент?
A>Распарсить большой файл, каждая строчка которого имеет формат вида: A>a1;a2;a3;a4;...;a200 A>Необходимо каждую такую строку преобразовать в объект наподобие: A>obj = ["a1", "a2", ..., "a200"]
Остаются маленькие вопросы в размере файла, кодировке и в необходимости возвращать коллекции для каждой сторки (итератора / элементов по одному недостаточно?).
Патамучта в случае определенных ответов можно читать байты и отсекать по разделителю и/или newline.
Здравствуйте, Aртём, Вы писали:
Aё>Только Java и C (без плюсанутых) спасут этот мир .
Тут, на форуме, скромно пытаюсь высказать такую же мысль.
Страуструп дополнил чистый C OOП-ом. ООП это важно в ЯП. На этом можно было бы
и остановиться. Но C++ превратился в пастбище праздных академиков, которые
курят то, что даже мыщъху не известно. Они превратили язык в демонстрацию
своей нужности и важности. Лучше бы тесселяционные шейдеры в Mesa разрабатывали,
и вообще занимались чем полезным.
Здравствуйте, smeeld, Вы писали:
S>Здравствуйте, alex_public, Вы писали:
_>>И соответственно этот код работает у меня где-то в 2,5 раза быстрее, чем его аналог на Питоне.
S>Осталось немного, и придёт, наконец, понимание, что здесь, в этой задачке, контейнеры и стримы вообще S>ни куда не упёрлись. Их нельзя использовать на каждый чих. Сформировать malloc-ом буфер с содержимым S>файла, разбить его на токены или предложения нуль терминатором, последовательно с занесением указателей в массив. S>Вот указатели, а лучше их unique_ptr, можно уже складывать в вектор. Только не забыть задать ему первоначальный S>размер отличный от нуля, а то vector, созданный дефолтным конструктором, сначала запрашивает память под объект, S> потом под два, копируя туда содержание предыдущего буфера и удаляя его, потом под четыре и так далее, кто-то S>скажет, что использовать такой способ организации буфера правильно?
Нет. Шаблоны фундаментальный и необходимый инструмент. Если Вас не затруднит прочитать
внимательней, то поймёте, что речь идёт о неаккуратном, бездумном
использовании контейнеров.
Здравствуйте, smeeld, Вы писали:
S>Здравствуйте, Няшка, Вы писали:
Н>>Веткой случаем не промахнулись?
S>Нет. Шаблоны фундаментальный и необходимый инструмент. Если Вас не затруднит прочитать S>внимательней, то поймёте, что речь идёт о неаккуратном, бездумном S>использовании контейнеров.
1. Vector — это шаблон
2. Рост которого не всегда сопровождается копированием данных — зависит от реализации и аллокатора
3. Если Вы работаете не только с однобайтовым английским языком, то создать хороший текстовый парсер не на шаблонах будет тугой задачей
4. Читать весь файл csv в память и разбивать терминатором, чтобы потом копировать memcpy/strcpy — это бредовая идея для домашнего программирования. Подумайте внимательно, как будет работать Ваше решение на большом файле?.. а на сервере в несколько потоков?..
Какая будет стратегия на ошибки выделения памяти??? Как будете отдавать процессорное время другим задачам??? Куча не нужных проблем появится.
80% людей оценивают свое мастерство выше среднего...
Здравствуйте, anatoly1, Вы писали:
A>Распарсить большой файл, каждая строчка которого имеет формат вида: A>a1;a2;a3;a4;...;a200 A>Необходимо каждую такую строку преобразовать в объект наподобие: A>obj = ["a1", "a2", ..., "a200"]
И что дальше? Обработать каждую строчку и забыть? Или поиметь весь файл в памяти в виде развесистой структуры?
Иными словами, что должно остаться в памяти после окончания парсинга файла?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, smeeld, Вы писали:
S>>Покапитанить решили? Не интересно так.
PD>Интересно или нет, но эту функцию никто здесь не упомянул. Получилось впечатление, что либо нужно писать что-то совсем уж вручную (как у тебя), или без STL никак не обойтись. Вот я и решил напомнить...
эта функция зависит от кодировки, а шаблоны нет
впрочем, собственная ее реализация для шаблона — копеечный вопрос
80% людей оценивают свое мастерство выше среднего...
char * __cdecl strtok (
char * string,
const char * control
)
#endif/* _SECURE_VERSION */
{
unsigned char *str;
const unsigned char *ctrl = control;
unsigned char map[32];
int count;
#ifdef _SECURE_VERSION
/* validation section */
_VALIDATE_RETURN(context != NULL, EINVAL, NULL);
_VALIDATE_RETURN(string != NULL || *context != NULL, EINVAL, NULL);
_VALIDATE_RETURN(control != NULL, EINVAL, NULL);
/* no static storage is needed for the secure version */#else/* _SECURE_VERSION */
_ptiddata ptd = _getptd();
#endif/* _SECURE_VERSION */
/* Clear control map */for (count = 0; count < 32; count++)
map[count] = 0;
/* Set bits in delimiter table */do {
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
} while (*ctrl++);
/* Initialize str */
/* If string is NULL, set str to the saved
* pointer (i.e., continue breaking tokens out of the string
* from the last strtok call) */if (string)
str = string;
else
str = _TOKEN;
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets str to point to the terminal
* null (*str == '\0') */while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
str++;
string = str;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */for ( ; *str ; str++ )
if ( map[*str >> 3] & (1 << (*str & 7)) ) {
*str++ = '\0';
break;
}
/* Update nextoken (or the corresponding field in the per-thread data
* structure */
_TOKEN = str;
/* Determine if a token has been found. */if ( string == str )
return NULL;
else
return string;
}
Н>впрочем, собственная ее реализация для шаблона — копеечный вопрос
Здравствуйте, Няшка, Вы писали:
Н>Пихните туда UTF — узнаете
Если доработать так, чтоб '\0' не вставлялось, то и utf переварит спокойно-
сравнение ведь побайтное, и неважно что означают эти байты и совокупности из них.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В версии на C++ аллоцируется много мутабельных строк, в то время как в версии на Python строки иммутабельные, для них просто берётся view. EP>Плюс, у тебя vector аллоцируется каждый раз создаётся заново, а нужно создать его только один раз и переиспользовать его capacity многократно.
Может быть дело еще и в ifstream. Возможно там буферизация реализована хуже чем в питоне (я не проверял).
Здравствуйте, Няшка, Вы писали:
Н>1. Vector — это шаблон
Vector-это контейнер, обобщённый с помощью шаблонов.
Н>2. Рост которого не всегда сопровождается копированием данных — зависит от реализации и аллокатора
У аллокатора только спрашивают указатель, вызывая его allocate, и ему же велят удалять кусок памяти, вызывая его deallocate. Всё.
С самим данныи контейнер делает что ему хочется. И vector, если вновь помещаемые данные превысят имеющийся объём,
вызывает allocate, копирует в новый буфер предыдущий, и вызывает deallocate предыдущему.
Н>3. Если Вы работаете не только с однобайтовым английским языком, то создать хороший текстовый парсер не на шаблонах будет тугой задачей Н>4. Читать весь файл csv в память и разбивать терминатором, чтобы потом копировать memcpy/strcpy — это бредовая идея для домашнего программирования. Н> Подумайте внимательно, как будет работать Ваше решение на большом файле?..
А никто и не спорит про большие файлы. Большие файлы никто копировать в ram и не собирался, не надо капитанить.
Приведённый в треде пример с маппингом и двумя указателями известен всем страждущим. Только в контексте задачи TC,
всё это тут накручивать будет лишним. Речь изначально велась об ускорении работы приложения.
И парсинг побайтовым сравнением можно проводить на тексте любой кодировки. Шаблон понадобится для определения конкретной специфики
сравнения при поиске, и выдачи результатов. И всё спокойно проделывается и без задействования контейнеров.
H> а на сервере в несколько потоков?.. Н> Какая будет стратегия на ошибки выделения памяти??? Как будете отдавать процессорное время другим задачам??? Куча не нужных проблем появится.
И чем здесь именно контейнеры на шаблонах обеспечат threading safe? Разруливать всё придётся так же, как и без использования контейнеров.
Здравствуйте, smeeld, Вы писали:
S>Здравствуйте, Няшка, Вы писали:
Н>>2. Рост которого не всегда сопровождается копированием данных — зависит от реализации и аллокатора S>У аллокатора только спрашивают указатель, вызывая его allocate, и ему же велят удалять кусок памяти, вызывая его deallocate. Всё. S>С самим данныи контейнер делает что ему хочется. И vector, если вновь помещаемые данные превысят имеющийся объём, S>вызывает allocate, копирует в новый буфер предыдущий, и вызывает deallocate предыдущему.
если данные не переехали, то их можно и не копировать
Н>>3. Если Вы работаете не только с однобайтовым английским языком, то создать хороший текстовый парсер не на шаблонах будет тугой задачей Н>>4. Читать весь файл csv в память и разбивать терминатором, чтобы потом копировать memcpy/strcpy — это бредовая идея для домашнего программирования. Н>> Подумайте внимательно, как будет работать Ваше решение на большом файле?..
S>А никто и не спорит про большие файлы. Большие файлы никто копировать в ram и не собирался, не надо капитанить. S>Приведённый в треде пример с маппингом и двумя указателями известен всем страждущим. Только в контексте задачи TC,
ТС в глобальном плане задачи не освещал
может он на серваке логи крутить в csv хочет и ищет вариант быстрее...
S>всё это тут накручивать будет лишним. Речь изначально велась об ускорении работы приложения.
Ускорение на 5 кб не имеет значения, любой вариант сгодится. Хоть на регулярках... затраты на современной технике будут копеешные.
Скорость актуальна в бигдата и высоконагруженном программировании.
Сколько миллисекунд там эксель непосредственно будет читать табличку из csv — всем насрать.
S>И парсинг побайтовым сравнением можно проводить на тексте любой кодировки. Шаблон понадобится для определения конкретной специфики S>сравнения при поиске, и выдачи результатов. И всё спокойно проделывается и без задействования контейнеров.
Можно, можно... яйца граблями чесать, но процесс и результат вряд ли будут удовлетворительными.
H>> а на сервере в несколько потоков?.. Н>> Какая будет стратегия на ошибки выделения памяти??? Как будете отдавать процессорное время другим задачам??? Куча не нужных проблем появится.
S>И чем здесь именно контейнеры на шаблонах обеспечат threading safe? Разруливать всё придётся так же, как и без использования контейнеров.
Если бахать всё сразу в память, то конечно тут помочь уже нечем.
80% людей оценивают свое мастерство выше среднего...
PD>>Хм... Что тут зависит от кодировки ?
Н>Пихните туда UTF — узнаете
Вообще-то strtok, как и string.h вообще, не предназначена для того, чтобы работать с UTF. Если UTF сунуть в обычную strlen, то результат, мягко говоря, будет тоже далек от истины. Да и вообще кроме strcpy/strcat мало что будет работать.
Здравствуйте, Няшка, Вы писали:
S>>всё это тут накручивать будет лишним. Речь изначально велась об ускорении работы приложения. Н>Ускорение на 5 кб не имеет значения, любой вариант сгодится. Хоть на регулярках... затраты на современной технике будут копеешные.
Изначально как раз и говорится, что затраты далеко не копеечные.
Н>Скорость актуальна в бигдата и высоконагруженном программировании. Н>Сколько миллисекунд там эксель непосредственно будет читать табличку из csv — всем насрать.
А эксель на атомном планшете? А эксель на мобилке? Поставим туда ксеон для ускорения?
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, Няшка, Вы писали:
S>>>всё это тут накручивать будет лишним. Речь изначально велась об ускорении работы приложения. Н>>Ускорение на 5 кб не имеет значения, любой вариант сгодится. Хоть на регулярках... затраты на современной технике будут копеешные.
N>Изначально как раз и говорится, что затраты далеко не копеечные.
А какого размера файл изначально? Явно не 5 кб.
Н>>Скорость актуальна в бигдата и высоконагруженном программировании. Н>>Сколько миллисекунд там эксель непосредственно будет читать табличку из csv — всем насрать.
N>А эксель на атомном планшете? А эксель на мобилке? Поставим туда ксеон для ускорения?
И там, и там есть. Работают и поверьте никто там над скоростью чтения таблиц голову не ломал, т.к. эксель не предполагает работу с большими таблицами.
80% людей оценивают свое мастерство выше среднего...
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Няшка, Вы писали:
PD>>>Хм... Что тут зависит от кодировки ?
Н>>Пихните туда UTF — узнаете
PD>Вообще-то strtok, как и string.h вообще, не предназначена для того, чтобы работать с UTF. Если UTF сунуть в обычную strlen, то результат, мягко говоря, будет тоже далек от истины. Да и вообще кроме strcpy/strcat мало что будет работать.
Вообще то предназначены, т.к. есть версии этих ф-ций для mb и utf-16 строк.
Просто на шаблонах легко накатать универсальную функцию, которая будет работать не зависимо от типа кодировки.
80% людей оценивают свое мастерство выше среднего...
Здравствуйте, Няшка, Вы писали:
Н>Здравствуйте, Nuzhny, Вы писали:
N>>Здравствуйте, Няшка, Вы писали:
S>>>>всё это тут накручивать будет лишним. Речь изначально велась об ускорении работы приложения. Н>>>Ускорение на 5 кб не имеет значения, любой вариант сгодится. Хоть на регулярках... затраты на современной технике будут копеешные.
N>>Изначально как раз и говорится, что затраты далеко не копеечные.
Н>А какого размера файл изначально? Явно не 5 кб.
Н>>>Скорость актуальна в бигдата и высоконагруженном программировании. Н>>>Сколько миллисекунд там эксель непосредственно будет читать табличку из csv — всем насрать.
N>>А эксель на атомном планшете? А эксель на мобилке? Поставим туда ксеон для ускорения?
Н>И там, и там есть. Работают и поверьте никто там над скоростью чтения таблиц голову не ломал, т.к. эксель не предполагает работу с большими таблицами.
Собсно, разговор как-то не туда завернул... Я хотел сказать, что местячковые, типа загнать всё в память, решения это не правильно.
Они дают результат на тестах и локальных задачах, но при переносе на реальные нагрузки дадут больше проблем.
80% людей оценивают свое мастерство выше среднего...
Здравствуйте, Lazin, Вы писали:
EP>>В версии на C++ аллоцируется много мутабельных строк, в то время как в версии на Python строки иммутабельные, для них просто берётся view. EP>>Плюс, у тебя vector аллоцируется каждый раз создаётся заново, а нужно создать его только один раз и переиспользовать его capacity многократно. L>Может быть дело еще и в ifstream. Возможно там буферизация реализована хуже чем в питоне (я не проверял).
Возможно, но я думаю вряд ли это решающий фактор (это надо было бы очень сильно накосячить) — потому что целый набор аллокаций стандартным аллокатором на каждую итерацию это реально медленно.
Это, кстати, подтверждается новым примером ТС
Здравствуйте, Няшка, Вы писали:
N>>А эксель на атомном планшете? А эксель на мобилке? Поставим туда ксеон для ускорения?
Н>И там, и там есть. Работают и поверьте никто там над скоростью чтения таблиц голову не ломал, т.к. эксель не предполагает работу с большими таблицами.
Ну, тогда мне просто остаётся надеяться, что ты не разрабатываешь продукты, которыми я пользуюсь. Удачи в работе!
Здравствуйте, anatoly1, Вы писали:
A>В итоге, думаю, остановлюсь на таком варианте: A>
A>int main()
A>{
A> std::ifstream f;
A> f.open("test.csv");
A> std:string s;
A> std::vector<std::string> sv(201);
A> std::stringstream ss;
A> std::string item;
A> while ( std::getline(f, s) )
A> {
A> ss.clear();
A> ss.str(s);
A> for (int i = 0; std::getline(ss, item, ';'); i++)
A> std::swap(sv[i], item);
A> }
A> return 0;
A>}
A>
Это конечно далеко не самый быстрый вариант, но можно и так. Тут два основных момента:
1. swap и item не нужны, можно считывать сразу в sv.
2. Размер вектора .size() нельзя уменьшать, иначе потеряется уже аллоцированная capacity в элементах-строках.
Как видно, при if (this->_M_impl._M_finish == this->_M_impl._M_end_of_storage) конструируются объекты по новому месту жительства, с переносом состояния.
Старому буферу делается Dealloc
Н>Вообще то предназначены, т.к. есть версии этих ф-ций для mb и utf-16 строк.
utf-16 , точно, есть, wcstok, но она опять же работает независимо от кодировки. Для mb — не знаю, по крайней мере в VC++
Н>Просто на шаблонах легко накатать универсальную функцию, которая будет работать не зависимо от типа кодировки.
Медленнее. При любой кодировке, кроме кодировок с одинаковым количеством байт, придется вместо p++ делать нечто более сложное.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Возможно, но я думаю вряд ли это решающий фактор (это надо было бы очень сильно накосячить) — потому что целый набор аллокаций стандартным аллокатором на каждую итерацию это реально медленно. EP>Это, кстати, подтверждается новым примером ТС
— избавившись от аллокаций на каждой итерации, он ускорился на порядок.
Я просто помню, что ifstream очень медленный и часто читает файл, если читать его через getline, может у него просто буфер внутри маленький. Я правда ifstream уже не помню когда в последний раз использовал, но судя по тому, что без аллокаций получилось просто достигнуть паритета с питоновским кодом, то дело может быть и в этом. В общем, хорошо бы ТС прочитал файл в память полностью, а потом уже распарсил, тогда можно будет понять в чем проблема.
Здравствуйте, Lazin, Вы писали:
L> В общем, хорошо бы ТС прочитал файл в память полностью, а потом уже распарсил, тогда можно будет понять в чем проблема.
Здравствуйте, anatoly1, Вы писали: A>С++ медленнее питона при парсинге файла.
питон это вообще просто продвинутая версия shell
A>std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) { A> std::stringstream ss(s); A> std::string item; A> while (std::getline(ss, item, delim)) { A> elems.push_back(item); МЕДЛЕННО, НУЖНО ПРЕАЛЛОЦИРОВАТЬ БУФЕР A> } A> return elems; A>}
A>std::vector<std::string> split(const std::string &s, char delim) { ВОЗВРАТ МАССИВА ПО ЗНАЧЕНИЮ ЭТО РАЗРУШЕНИЕ СТАРОГО И КОНСТРУИРОВАНИЕ НОВОГО. ОЧЕНЬ МЕДЛЕННО
A>Boost'овский split, кстати, ещё медленней работает. A>В чём может быть причина такой низкой производительности у С++?
обычно, кстати в split нет никакого смысла. мы или что-то ищем конкретное или обрабатываем данные кусками. зачем сплитить массив перед обработкой? Поэтому правильное время работы split в С++ 0 секунд, потому что split там не нужен
Здравствуйте, anatoly1, Вы писали:
A>В чём может быть причина такой низкой производительности у С++?
Руки выпрямлять пробовали?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, __kot2, Вы писали:
A>>Boost'овский split, кстати, ещё медленней работает. A>>В чём может быть причина такой низкой производительности у С++? __>обычно, кстати в split нет никакого смысла. мы или что-то ищем конкретное или обрабатываем данные кусками. зачем сплитить массив перед обработкой? Поэтому правильное время работы split в С++ 0 секунд, потому что split там не нужен
действительно. дело не в плюсах. это задача недостаточно хорошая для них.
Здравствуйте, neFormal, Вы писали: F>действительно. дело не в плюсах. это задача недостаточно хорошая для них.
эта задача — подготовка данных для обработки инструментами питона. она бессмысленна сама по себе без питона
Здравствуйте, __kot2, Вы писали:
F>>действительно. дело не в плюсах. это задача недостаточно хорошая для них. __>эта задача — подготовка данных для обработки инструментами питона. она бессмысленна сама по себе без питона