
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.217.2] |
![]() |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
![]() |
Сообщ.
#1
,
|
|
Язык не важно какой, важна суть, читаем большой файл (10-50МБ) а может и больше
пример для понятности на "проклятом" всеми чистом C, просьба холиваров на темы C++ лучше, не разводить, ![]() ![]() ![]() char buf[1024*512]; while (fgets(buf, sizeof(buf), fp) != NULL) { buf[strlen(buf) - 1] = '\0'; // eat the newline fgets() stores printf("%s\n", buf); } Как подбирать оптимальный размер баффера? почему .5мега а не 2 или 10? Данные приходят по сети, обычным HTTP, В сети гуглил толком ничего по сути не нашел, какие варианты ![]() |
Сообщ.
#2
,
|
|
|
1. Размер должен быть кратен степени двойки, коли сейчас почти все машины считают в двоичной, да и аппаратная поддержка, скорее всего, этим пользуется.
2. Не надо размер в несколько мегабайт (не больше), т.к. старые машины могут не найти столько памяти, а делать желательно для бо́льшего количества применений. 3. Главное: размер должен быть таков, чтобы время на количество вызовов функций для чтения (с учётом времени на вызов каждой) было незначительно в сравнении с временем чтения данных. Так, для SSD, скажем, желательно делать вызовов поменьше, ибо они данные читают шибче. Впрочем, предел=идеал всё равну будет манить: только 1 вызов. В то же время, если вдруг делаете попытки чтения битых файлов, то запросто может оказаться, что лучше наделать кучу микровызовов (чтобы хоть что-то прочитать), нежели всего один, кой скажет, что неудача,... и адью. ![]() |
Сообщ.
#3
,
|
|
|
На самом деле даже для относительно медленных жёстких дисков нет смысла слишком увеличивать размер буфера. Ведь пока буфер заполняется, программа ждёт, и ничего не делает. По крайней мере нет смысла делать его больше, чем дорожка диска (128 кБ). На само деле нет смысла делать его длиннее основной части непрерывных сегментов файла. Из-за этого для обычной последовательной обработки в современных операционных системах для современных же жёстких дисков обычно обходятся буфером размером в 4-64 КБ (Для винды покороче, для линукса подлиннее, обычно 16). Операционная система обнаружив, что программа читает файл последовательно с самого начала, сама считывает файл в кэш диска, и выдаёт порциями. При произвольном доступе имеет смысл делать буфер короче.
Увеличение размера буфера имеет смысл при копировании файлов в пределах одного физического носителя (с механическим доступом). Но, для того, чтобы получить существенный выигрыш, недостаточно задавать буфер в вызовах функций fread/fwrite. Надо задать размер внутреннего буфера файла, используемого низкоуровневыми read/write. |
Сообщ.
#4
,
|
|
|
Славян и amk, вы вроде челы продвинутые, на такие косяки порете!
![]() 1) Славян, возьми "среднестатистический" винт 10-й давности, там аппаратный кэш уже порядка 32 Mb! А это значит - "впилил и забыл", остальное дело микросхем. Вывод - "пилить" меньше, только электричество портить! 2) Amk, твое "ведь пока буфер заполняется, программа ждёт, и ничего не делает. По крайней мере нет смысла делать его больше, чем дорожка диска (128 кБ)." - шедевр безалаберности! Ты уж извини ... Про асинхронность помним, не? Отдали винту "порцию", не ждем ответа - работаем дальше. Давай вместе почитаем? Не поймите, плс, меня превратно - я не спец в этом вопросе, и код не "выплюну" на раз-два. Но, концептуально, я - в теме. И чуйка подсказывает, что вы неправы. Очень глубоко, в своих глубинах ![]() |
![]() |
Сообщ.
#5
,
|
|
Цитата amk @ Но, для того, чтобы получить существенный выигрыш, недостаточно задавать буфер в вызовах функций fread/fwrite. Надо задать размер внутреннего буфера файла, используемого низкоуровневыми read/write. А как знать какой размер внутреннего буфера файла? У меня java, выглядит это ![]() ![]() InputStream inputStream = request.getInputStream(); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); и потом ![]() ![]() char[] charBuffer = new char[8*1024] while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { } Я его (файл ) парсю в HTTP handler, еще я знаю что это csv. Пока писать на C не могу(слишком много народу, фирма 1500человек, убеждать надо). дать 16 для Лины и 8 для окон, будет нормально? |
Сообщ.
#6
,
|
|
|
sergioK, рекомендую тебе подход - системный!
В ближнем приближении - твоя "система" тупо состоит из двух блоков "ввод" и "вывод". Количество там и там - роли не играет. Важен трансфер на входе и выходе. Берем "вход", ты писал HTTP. Там существенным критерием есть MTU. Но он крошечный - единственный разумный, имхо, момент - делать буффер кратный ему. На счет блоков вывода - я бы смотрел в сторону аппаратных возможностей записи. Уже писал выше - как минимум размера аппаратного кэша. Но есть и третий момент, который забывают очень часто!!! А именно - свободная память для ОС! Если об этом не заботиться - ОС переходит в жесткий режим свопа - а это, в плане производительности, считай - "обнять и плакать"! Таким образом, любые манипуляции с памятью не должны урезать разумные границы работы ОС. Это самое главное!!! Оно - самое самое, и оно - самое главное! Остальное - лайт тюнинг. Таковое мое ИМХО. |
Сообщ.
#7
,
|
|
|
Цитата JoeUser @ Я комментировал пост с вызовом fgets. Там никакой асинхронности в принципе быть не может. Так что вызываем функцию… и ждём.Про асинхронность помним, не? Отдали винту "порцию", не ждем ответа - работаем дальше. Впрочем для fgets выбор размера буфера определяется по-другому. Буфер должен быть больше, чем самая длинная строка в файле. Буфер записи для fputs/fwrite может быть любым. Вообще любым, всё равно данные из него просто переписываются в буфер управления файлом. Буфер записи для write тоже любой, лишь бы был кратен размеру блока системного файлового кэша. Система сама разберётся когда и что писать на диск. Буфер чтения для read тоже должен быть кратен блоку системного кэша. И, повторю, нет смысла делать его больше, чем непрерывная цепочка блоков в файле, никакого выигрыша по быстродействию не будет. С другой стороны нежелательно делать его меньше читаемой за один раз порции данных. Если обработка идёт медленно по сравнению с чтением, то буфер можно вообще сделать примерно равным одной порции. Цитата JoeUser @ Вижу, поскольку "выплёвывание" кода тут вообще дело десятое. Всё зависит от того, какая система и куда идёт запись (откуда идет чтение). С некоторыми устройствами выгоднее вообще работать по-байтно. Не поймите, плс, меня превратно - я не спец в этом вопросе, и код не "выплюну" на раз-два. |
![]() |
Сообщ.
#8
,
|
|
Цитата JoeUser @ Уже писал выше - как минимум размера аппаратного кэша. Но есть и третий момент, который забывают очень часто!!! А именно - свободная память для ОС! несколько гига хватит ? Асинхронность тоже ничего не даст, пока данные необработаны делать нечего, ну поставишь waitSingleThread, все поймут что крутой пацан ![]() Всем спасибо но это была теория, что делать практически ? Ну я дам возможность размер буфера брать из конфига, и ловить оптимальный вариант методом try && mistakes ? Что конкретно в коде писать ?. |
Сообщ.
#9
,
|
|
|
Цитата amk @ Буфер записи для fputs/fwrite может быть любым. Вообще любым, всё равно данные из него просто переписываются в буфер управления файлом. Буфер записи для write тоже любой, лишь бы был кратен размеру блока системного файлового кэша. Система сама разберётся когда и что писать на диск. Буфер чтения для read тоже должен быть кратен блоку системного кэша. И, повторю, нет смысла делать его больше, чем непрерывная цепочка блоков в файле, никакого выигрыша по быстродействию не будет. я вот опять недавно разбирал старую программу для Виндус , и легко поднял производительность её отрезка с файловыми операциями на порядок (в 10 раз). Там чтение файла 200-300К происходило по-байтно. А если читать блоками 16К-32К (актуальное значение буфера - размер кластера, 4К) производительность выросла в 10 раз. --- Как то раз я написал тест, для исследования зависимости скорости от размеров буфера с блочной операцией fread/fwrite. Основной выигрыш был, когда буфер достигал 4К. Дальше бонус растёт очень медленно, в том случае, если речь идёт о файлах огромных размеров. Просто за счёт уменьшения количества циклов и обращений к fread/fwrite. Добавлено Цитата sergioK @ Всем спасибо но это была теория, что делать практически ? Проведи исследование. Возьми какой-нибудь огромный файл. И измеряй время его чтения, в зависимости от величины буфера. |
![]() |
Сообщ.
#10
,
|
|
Цитата JoeUser @ 2) Amk, твое "ведь пока буфер заполняется, программа ждёт, и ничего не делает. По крайней мере нет смысла делать его больше, чем дорожка диска (128 кБ)." - шедевр безалаберности! Ты уж извини ... Про асинхронность помним, не? Отдали винту "порцию", не ждем ответа - работаем дальше. Давай вместе почитаем? Вообще-то он прав - не нужно делать больше, чем размер кластера. Да и асинхронность тут никаким боком - она не уменьшит время, проходящее с момента запуска начала чтения до его конца. |
Сообщ.
#11
,
|
|
|
Цитата OpenGL @ Вообще-то он прав - не нужно делать больше, чем размер кластера. Да и асинхронность тут никаким боком - она не уменьшит время, проходящее с момента запуска начала чтения до его конца. Она уменьшит количество операций с контроллером винта. А это существенно. |
![]() |
Сообщ.
#12
,
|
|
Цитата JoeUser @ Она уменьшит количество операций с контроллером винта. Дай пруф на существенность что ли. |
Сообщ.
#13
,
|
|
|
Цитата OpenGL @ Дай пруф на существенность что ли. Ну выше же писали уже, мол блочное чтение/запись увеличивает на порядок скорость, нежели посимвольное чтение. Если доверия нет - напиши короткий тест. Я давно это проверял, и помню хорошо. Еще писамши на Virtual Pascal'е. Тут сравнивается заведомо худший вариант с "каким-то", путь удовлетворительным. И разница видна. А вот дальше нужно определиться с понятием "существенно". Это от задачи к задаче, ИМХО. В два раза - это существенно? А на 5% быстрее, существенно? По-моему так: коль ТС заговорил о быстродействии - значит любой лучший результат существенен. Ну как-то так. |
![]() |
Сообщ.
#14
,
|
|
Цитата JoeUser @ Ну выше же писали уже, мол блочное чтение/запись увеличивает на порядок скорость, нежели посимвольное чтение. Давай ты не будешь додумывать то, что я не говорил. О том, что посимвольное чтение медленней буферизованного никто не спорит. Речь о том, что нет смысла делать буфер большой - 64 кб, например, за глаза и уши, а лучше и того меньше. Увеличение его размера не только не приведёт к ускорению, но даже замедлить чтение может. Добавлено Цитата JoeUser @ По-моему так: коль ТС заговорил о быстродействии - значит любой лучший результат существенен. Если жалкие проценты в быстродействии важны, то проще всего сделать размер буфера конфигурируемым, и на конкретной системе уже и выбирать наиболее подходящий размер. |
Сообщ.
#15
,
|
|
|
Цитата OpenGL @ Речь о том, что нет смысла делать буфер большой - 64 кб, например, за глаза и уши, а лучше и того меньше. Возникает резонный вопрос - зачем тогда HDD обеспечивают аппаратным кэшем в 64/32/16/8 MB? ![]() |