доброго времени суток, очень бы хотелось узнать: пробегая по дереву каталогов рекурсией, что лучше использовать для работы с файлами, мэппинг или непосредственное использование функций readfile&writefile, и почему ?
Ну, вроде в ядре есть только отображение. То есть при вызове CreateFile(..., GENERIC_READ... ) происходит отображение файла в память ядра. И ReadFile() просто копирует оттуда данные. Так что теоретически это всё равно. Практически: 1. Иногда отображение удобнее использовать. 2. Если отображать большой файл (700 Мб), то будет очень тормозно (у меня так). А если отображать его поочерёдно порциями по 100 Кб, то не будет никакой разницы между отображением и обычным чтением. В последнем случае ReadFile() даже проще.
По поводу отображения дольшого файла, то тормозить не будет всё равно. Кэш менеджер и так в память всё не возьмет. И вообще все эти отображения гениально продуманы в плане удобства и оптимизации. А по поводу ReadFile() - то да это проще, но вот и менно, что при ReadFile() копируются данные в буфер, а MapViewOfFile просто настраивает виртуальные адреса на блок, где на самом деле спроецирован файл. Тем более при вызове MapViewOfFile подпроцедур вызывается меньше, чем при ReadFile().
Тогда возникает вопрос: до CreateFile механизм в принципе одинаков для обоих способов, а различия начинаются уже после ?
> И еще хотелось бы узнать, что на происходит при выхове CreateFileMapping. The CreateFileMapping function creates a named or unnamed file-mapping object for the specified file. Return Values If the function succeeds, the return value is a handle to the file-mapping object.
Я понимаю, MSDN и у меня есть, меня интересует внутренний механизм работы, если вопрос этот неуместен здесь, то хотя бы где искать описание.
Описание поискать в IDA. Дизассемблируются три файла - kernel32.dll/ntdll.dll/ntoskrnl.exe. И вопрос уходит.
PavPS Если ReadFile копирует в буфер, то я так понял, что это хранится в ОЗУ, а при MapViewOfFile сами данные где хранятся, т.е. куда спроецирован файл, и откуда читаются данные? Судя по распределению памяти, при MapViewOfFile в оперативную память они не загружаются, например MapViewOfFile для файла 30-40 Мб никак не увеличивает выделение памяти. Получается они (данные) так и остались на винте. Если так, то не получится для файлов такого размера, что с ReadFile будет гораздо быстрее доступ к данным, хранящимся в оперативной памяти, чем с MapViewOfFile, если в последнем случае данные приходится доставать с винта?
Блин, объснял же: При открытии файла его чать проецируется на область памяти ядра. ReadFile() именно оттуда и читает, а MapViewOfFile() настраивает адреса так, что при чтении-записи страниц памяти, на которые спроецирован файл, происходит либо чтение из кэша, либо подкачка с диска. Так что всё одно, если не считать того, что ReadFile() тратит время на пересылку данных в буфер пользователя.
Foamplast ReadFile() тратит время на пересылку данных в буфер пользователя Afaik если файл открыт с использованием FILE_FLAG_NO_BUFFERING, то этого не происходит.
Вообще, тема это большая и сложная, как мне кажется. Больше всего ответов, действительно из IDA + SoftIce. Так же не обойтись без David A. Solomon and Mark E. Russinovich с их гнигой InWin2k. Вопрос файловых отображений и дисковых IO ессно затрагивает Cache Manager-а. Все чтения с диска идут через IoPageRead. Эта функция и получает живенькие байтики с винта/диска. Ну вообще, если быть точнее, то облагораживает данные и посылает к девайсу нужного устройства. Соответствующие драйвера связываются с CcCopyRead, которая окончательно находит девайс, соответственный за это устройство и читает уже данные. Данные попадают в кэш, строение которого замечательно описано у Соломона. Причем, чё я заметил, то что они всегда попают в кэш сначалаТак вот, если вазвано чтение было через ReadFile, то потом из кэша данные попадают в Твой буфер (rep movsd). Если же это MavPiewOfFile, то адреса виртуальные настраиваются на кэш, а он ессно ограничен в своих размерах. Ну да ладно, итак, вазвав MavPiewOfFile для 40 метрового файла в КЭШе и памяти будет только часть, а остальные адреса, соответствеющие большим смещениям в файле поначалу будет инвалидными. При попытке прочитать их будет вызван PageFault, который просит разобраться во всём ф-ю IoPageRead, и страничка подгружается… вот в принципе и всё.. По поводу быстродействия – это всё таки MavPiewOfFile. Причем, всего лишь при первом обращении к файлу, он уже кэшируется. Пусть Ты даже размер только его проверял. (на моей практике так было) Так же из практики выяснил, что любой файл пишется ч/з ф-ю CcWrite. P.S. Очень буду рад побеседовать на эту тему. Самому очень интересно, да и работа простаивает из-за этой темноты…
PavPS Я тут маленький эксперимент сделал по поводу MapViewOfFile vs ReadFile, суть такова: Первый эксперимент: 1. CreateFile > CreateFileMapping > MapViewOfFile 2. Выполнение действий с этим "отображением" по всему объёму файла. Второй эксперимент: 1. CreateFile > GlobalAlloc > GlobalLock > ReadFile 2. Выполнение действий со всем объёмом, считанным в ОЗУ Для MapViewOfFile я очень быстро получаю доступ к объекту обработки (содержимому файла), но работается с ним очень медленно, ReadFile же наоборот, заставляет ждать полной загрузки, но затем обработка данных происходит быстро. Для "выполняемых действий" выбрал процедуру сортировки, т.к. она одновременно работает со всем объёмом. Результаты примерно такие (цифры ни о чем не скажут, но пропорции верные) MapViewOfFile - получение отображения и готовность к действиям - 15-30 мс, обработка данных - 2000-3000 мс ReadFile - получение данных и готовность к обработке - 2000-2500 мс, обработка данных - 140-150 мс. Процедура обработки одна и та же. Можно ли как-нибудь совместить достоинства обоих способов: быстроту готовности к обработке MapViewOfFile и скорость обработки за счёт того, что все данные в озу (ReadFile)? Или это невозможно?
Ну вообще, я тоже эксперементировал. Ну возьми файл 200 метров и открой его для просмотра (totalcommander::F3)прокрути вниз/верх и так много раз. Сначала будет тормозить а потом даже и к винту обращаться не будет. А результат Твой, впрочем, ожидаемый. А чё ты хотел, у MapViewOfFile куча приемуществ, что не так уж и заметны Твои недостатки в скорости. А вообще странно. Поидее, после первого прохода по всему объему данных, последующие проходы должны быть без тормозов. А вообще стоит тут посмотреть на зависимость скорости от NonePaged/Paged memory pools.
> IMHO этот PageFault и тормозит. Я тоже делал небольшие эксперименты и результаты похожие как у cresta. Пришёл к такому выводу: если нужно обработать файл целиком, то быстрее будет ReadFile. Если же нужны только какие-то части файла, и/или доступ к ним происходит "время от времени", тогда лучше MapViewOfFile. Короче, что лучше от задачи больше зависит.
Не знаю, кто такой PageFault, но из наблюдений за винтом при MapViewOfFile: при обработке данных винт крутится на полную катушку. Т.е. тормозит то, что данные берутся непосредственно с винта. Причём данные остаются в озу: в начале обработки под процесс выделено 1 Мб, к концу обработки выделение для процесса составляет 27-28 Мб. Получается, MapViewOfFile имеет преимущества, когда нельзя считать файл целиком, а при объёмах памяти, которые винда может выделить без особого напряга, с ReadFile быстрее. Или в случае работы с маленьким куском большого файла. Хотя где-то читал, что MapViewOfFile следует использовать где только можно