Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.02.12;
Скачать: [xml.tar.bz2];

Вниз

Самый быстрый способ считать маленький файл в строку   Найти похожие ветки 

 
Nucer   (2011-10-13 15:59) [0]

Подскажите самый быстрый способ считать файл в RawByteString. Необходимо обрабатывать около 50 тысяч файлов размеров в 100-200 килобайт.

При таком варианте только на чтение без обработки уходит минут 5:
var
 S: RawByteString;
 F: File;
 Size: Int64;
begin
 AssignFile(F, Filename);
 Reset(F, 1);
 Size := FileSize(F);
 Reset(F, Size);
 SetLength(S, Size);
 BlockRead(F, S[1], 1);
 CloseFile(F);
end;


 
Плохиш ©   (2011-10-13 16:02) [1]

TFileStream


 
Омлет ©   (2011-10-13 16:07) [2]

> Плохиш ©   (13.10.11 16:02) [1]
> TFileStream


Ага, как будто он вызывает какую-то другую функцию для чтения файла (ReadFile).


 
Омлет ©   (2011-10-13 16:11) [3]

> Nucer   (13.10.11 15:59)

Ты выделяешь память под каждый файл, а потом освобождаешь. А можно выделить один раз большой буфер и с ним работать. И не завязывайся на строки (что такое RawByteString?), работай напрямую с памятью через указатели.


 
Омлет ©   (2011-10-13 16:15) [4]

И не надо вызывать FileSize, почитай справку по BlockRead.


 
Nucer   (2011-10-13 16:19) [5]

Выделение памяти на фоне чтения файла выполняется мгновенно. Если убрать строку и читать из файла только один байт, то времени на чтение всех файлов уходит примерно столько же (по байту с каждого).
С TFileStream быстрее не стало. На один файл уходит около 30 ms. 50 тысяч файлов - около 25 минут. Ужасно долго. Программно никак не ускорить процесс?


 
stas ©   (2011-10-13 16:25) [6]

Nucer   (13.10.11 16:19) [5]
А если отключить антивирус?


 
Ega23 ©   (2011-10-13 16:27) [7]


> 50 тысяч файлов - около 25 минут.


А щито вы хотели? Дисковая операция.


> Программно никак не ускорить процесс?


Ну если более одного ядра, то можно попробовать распараллелить потоки.


 
Nucer   (2011-10-13 16:28) [8]

> А если отключить антивирус?
Отключил первым делом :)


 
Омлет ©   (2011-10-13 16:30) [9]

Какая файловая система? Какой носитель?


 
Ega23 ©   (2011-10-13 16:30) [10]

Потом что-то ещё такое было про количество файлов в директории. Мол, после какого-то количества (1000, например) сканирование начинает ощутимо подтормаживать.
Впрочем, с этим к Розычу.


 
Nucer   (2011-10-13 16:32) [11]

> Какая файловая система? Какой носитель?
NTFS, HDD (SATA 5400)

> Ega23 ©   (13.10.11 16:30) [10]
Попробую раскидать по папкам, вдруг поможет.


 
Омлет ©   (2011-10-13 16:33) [12]

Сильно ли разбросаны файлы по диску?


 
Ega23 ©   (2011-10-13 16:35) [13]

Ещё один вариант: не делать 50.000 маленьких файлов, а сделать один большой из 50.000 частей.


 
sniknik ©   (2011-10-13 16:37) [14]

> около 50 тысяч файлов размеров в 100-200 килобайт.
а сколько времени занимает например копирование их системой? запись конечно дольше но порядок цифр будет показателен...
один большой файл копируется быстрее чем много много мелких. даже при том что размер большого в много раз больше суммы мелких.


 
Anatoly Podgoretsky ©   (2011-10-13 16:39) [15]

> Nucer  (13.10.2011 16:19:05)  [5]

30 миллисекунд это скорость равна 30-60 мб/сек
Вроде бы это нормально для диска.


 
Dennis I. Komarov ©   (2011-10-13 17:51) [16]

50000 файлов вдруг оказываются? Может поменять логику и обрабатывать их по мере появления (ReadDirectoryChangesW), или вообще исключить файловый обмен в пользу TCP?


 
RWolf ©   (2011-10-13 17:53) [17]

вариант: не подгружать файл в буфер вообще.
вместо этого получать отображение файла на память (CreateFileMapping и т. д.).


 
Inovet ©   (2011-10-13 18:02) [18]

> [10] Ega23 ©   (13.10.11 16:30)
> Мол, после какого-то количества (1000, например) сканирование
> начинает ощутимо подтормаживать.

Это на ФАТ, там поиск не индексированный.


 
Inovet ©   (2011-10-13 18:03) [19]

> [5] Nucer   (13.10.11 16:19)
> На один файл уходит около 30 ms. 50 тысяч файлов - около 25 минут. Ужасно долго.

Зажрались однако.


 
Игорь Шевченко ©   (2011-10-13 20:11) [20]

Смотря зачем читать


 
Slym ©   (2011-10-14 07:24) [21]

4,3 секунды 50тыс открытие и "чтение" 1 файла в 356мб
procedure TForm1.Button2Click(Sender: TObject);
const FileName="D:\_films\Bones.s03e01.HDTVRip.NovaFilm.TV.avi";//356мб
var
 t:dword;
 i:integer;
 hFile,hMap:THandle;
 hMem:pointer;
begin
 t:=GetTickCount;
 for i:=0 to 50000 do
 begin
   hFile:=CreateFile(PChar(FileName),GENERIC_READ,FILE_SHARE_READ,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);
   hMap:=CreateFileMapping(hFile,nil,PAGE_READONLY,0,0,nil);
   hMem:=MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);
   UnmapViewOfFile(hMem);
   CloseHandle(hMap);
   CloseHandle(hFile);
 end;
 t:=GetTickCount-t;
 Caption:=InttoStr(t);
end;


 
MBo ©   (2011-10-14 08:53) [22]

Просто вход в папку с 20тыс мелких файлов FAR или проводником (в режиме без иконок) в первый раз занимает около минуты, во второй раз несколько секунд, но тоже не мгновенно.


 
han_malign   (2011-10-14 09:06) [23]


> открытие и "чтение" 1 файла в 356мб

- не правильный тест:
1. чтения, собственно, не происходит... - надо обратиться к странице памяти, чтобы она подгрузилась(Page Fault)...
2. файл в кэше(даже после закрытия(как минимум метаданные))...

- но направление мысли правильное...
1. сбоев страниц памяти не меньше чем в случае если каждый раз буфер создавать(зависит от менеджера памяти), зато нет дополнительного заполнения нулями(см. VirtualAlloc)...
2. (IMHO) поток не переходит в альтернативное состояние(на ReadFile) и соответственно есть шанс не потерять лишний квант(из тех 2-х, которые 30мс)...

З.Ы. еще можно попробовать FILE_FLAG_SEQUENTIAL_SCAN(без File Mapping), но по этому поводу у меня некоторые сомнения(поможет ли чем-то удвоенный буфер предвыборки если читаешь все?)...


 
han_malign   (2011-10-14 09:15) [24]


> Просто вход в папку с 20тыс мелких файлов FAR или проводником (в режиме без иконок) в первый раз занимает около минуты

- добавление 20тыс элементов в TListView(не виртуальный) занимает минут пять(без побочной работы)...
Это надо "чистый" тест делать, и отдельный поток на заполнение списка тоже никто не запрещал(если порядок обработки не имеет значения).


 
MBo ©   (2011-10-14 09:26) [25]

>обавление 20тыс элементов в TListView
В Far примерно то же самое.
И  я сталкивался с тем, что FindFirst/Next безо всяких гуёв по подобным папкам выполняется в первый раз ощутимое время


 
han_malign   (2011-10-14 10:05) [26]


> И  я сталкивался с тем, что FindFirst/Next безо всяких гуёв по подобным папкам выполняется в первый раз ощутимое время

- проверка прав - скорее всего...
Можно попробовать поиграться с владельцем, наследованием и т.д., но правильнее всего разбивать такую лапшу на дерево подпапок(при грамотном именовании можно делать(загрубленно) и фильтрацию, и сортировку)...

З.Ы. Сам не проверял, но некоторые клиенты утверждают, что после 64К наступает полная опа...


 
QAZ   (2011-10-14 10:47) [27]


> Nucer   (13.10.11 16:19) [5]

ктож блин, читает файлы по байту?
минимальная единица чтения должна быть равна размеру кластера
а при твоих размерах нужно читать весь файл зараз


 
han_malign   (2011-10-14 11:03) [28]


> ктож блин, читает файлы по байту?

- кури мануал...
procedure Reset(var F: file; RecSize: Integer);


 
QAZ   (2011-10-14 11:27) [29]


> han_malign   (14.10.11 11:03) [28]

данунафиг я такими файлофункциями в жизни не пользовался и не собираюсь


 
Slym ©   (2011-10-14 11:28) [30]

первый запуск 29700:10215 т.е. 30 сек по всему диску d:\ по маске pas+dcu найдено 10215 файлов
второй запуск 9900:10215
чтение побайтовое :) REPNE   SCASB

function LCharPos(Str:PChar;char:char;Size:integer): Integer;
asm  {Str - EAX, char - DL (EDX), Size - ECX}
       PUSH    EDI
       MOV     EDI, EAX { Point EDI to str}

       MOV     AL,DL        { AL = Search char}
       MOV     EDX,ECX   {remember Length}

       REPNE   SCASB
       JNE     @@fail
       MOV     EAX,EDX { Calc offset }
       SUB     EAX,ECX
       JMP     @@fin
@@fail:
       XOR     EAX,EAX
@@fin:
       POP     EDI
end;

procedure FastOpenFile(const FileName:string);
var
 i:integer;
 hFile,hMap:THandle;
 hMem:pointer;
begin
 try
 hFile:=CreateFile(PChar(FileName),GENERIC_READ,FILE_SHARE_READ,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);
 if hFile=INVALID_HANDLE_VALUE then RaiseLastOSError;
 hMap:=CreateFileMapping(hFile,nil,PAGE_READONLY,0,0,nil);
 if hMap=0 then RaiseLastOSError;
 hMem:=MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);
 if hMem=nil then RaiseLastOSError;
 LCharPos(hMem,#1,GetFileSize(hFile,nil));
 UnmapViewOfFile(hMem);
 CloseHandle(hMap);
 CloseHandle(hFile);
 except
 end;
end;

procedure TForm1.EnumFolder(dir:string);
var
 f:WIN32_FIND_DATA;
 hf: HFile;
 flag: boolean;
begin
 dir:=IncludeTrailingPathDelimiter(dir);
 hf:=FindFirstFile(PChar(dir+"*.*"),f);
 while FindNextFile(hf,f) do
 begin
   if (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)>0 then
   begin
     if (StrComp(f.cFileName,".")<>0) and (StrComp(f.cFileName,"..")<>0) then
       EnumFolder(dir+f.cFileName);
   end else
   begin
     if (pos(".pas",f.cFileName)>0) or (pos(".dcu",f.cFileName)>0) then
     begin
       inc(fc);
       FastOpenFile(dir+f.cFileName);
     end;
   end;
 end;
 windows.FindClose(hf);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 t:dword;
begin
 fc:=0;
 t:=GetTickCount;
 EnumFolder("d:\");
 t:=GetTickCount-t;
 Caption:=InttoStr(t)+":"+InttoStr(fc);
end;


 
Inovet ©   (2011-10-14 12:01) [31]

> [22] MBo ©   (14.10.11 08:53)
> Просто вход в папку с 20тыс мелких файлов FAR или проводником
> (в режиме без иконок) в первый раз занимает около минуты,
> во второй раз несколько секунд, но тоже не мгновенно.

Так он их имена и пр. грузит в свои структуры, а для открытия файла достаточно найти один в каталоге. На NTFS это быстро - каталог двоичное дерево, на FAT долго - каталог линейный.


 
Игорь Шевченко ©   (2011-10-14 20:11) [32]

цель чтения файлов не озвучена.


 
Rouse_ ©   (2011-10-14 20:28) [33]


> REPNE   SCASB

ужс, кто "такому ассемблеру" учит? Это из старых дельфийских библиотек или самописка?


 
Игорь Шевченко ©   (2011-10-14 20:41) [34]

Rouse_ ©   (14.10.11 20:28) [33]

Нормальный ассемблер


 
Rouse_ ©   (2011-10-14 20:50) [35]


> Rouse_ ©   (14.10.11 20:28) [33]
> Нормальный ассемблер

Интеловские мануалы в плане профилирования кода с тобой не согласны, особливо в части рекомендаций по использованию исключающих префиксов опкодов первой группы (из четырех):

 pfxRepn = $F2;
 pfxRep = $F3;


куда идут инструкции типа REPNE/REPNZ и т.д. тратящие пять тиков минимум  на итерации, так и инструкции LOOP например...
Впрочем ты и сам это должен помнить...


 
Игорь Шевченко ©   (2011-10-14 20:56) [36]

Во-первых, на цитату из мануала нефигово приводить ссылку.
Во-вторых, открываем внутренности VCL и видим примеры нормального ассемблера.
В-третьих, помним первый принцип оптимизации - по возможности ее избегать.


 
Rouse_ ©   (2011-10-14 20:57) [37]

ЗЫ: кусок из реализации дизасма, где описаны все 4 группы префиксов (если я не прав - поправь, скажу спасибо):

const
 // Lock and repeat prefixes:
 pfxLock = $F0;
 // The LOCK prefix can be prepended only to the following instructions and only to those forms
 // of the instructions where the destination operand is a memory operand: ADD, ADC, AND,
 // BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR,
 // XADD, and XCHG

 pfxRepn = $F2;
 pfxRep = $F3;

 // Segment override prefixes:
 pfxCSSegmentOverride = $2E;
 pfxSSSegmentOverride = $36;
 pfxDSSegmentOverride = $3E;
 pfxESSegmentOverride = $26;
 pfxFSSegmentOverride = $64;
 pfxGSSegmentOverride = $65;

 // Operand-size override prefix
 // (when used with the escape opcode 0FH, this
 // is treated as a mandatory prefix for some SIMD instructions)
 pfxOperandSizeOverride = $66;
 pfxEscapeOpcode = $0F;

 // Address-size override prefix
 pfxAddressSizeOverride = $67;


 
Anatoly Podgoretsky ©   (2011-10-14 21:06) [38]


> ужс, кто "такому ассемблеру" учит?

Это пример не профессионализма. Тупо сделаный код. Не читая ни умных книг, не руководство по оптимизации от Интела, не вглядываясь в генофонд.


 
Rouse_ ©   (2011-10-14 21:09) [39]


> Игорь Шевченко ©   (14.10.11 20:56) [36]
> Во-первых, на цитату из мануала нефигово приводить ссылку.

Ну блин: http://developer.intel.com/design/pentiumii/manuals/245127.htm
Ну и до кучи: http://agner.org/optimize/


 
Rouse_ ©   (2011-10-14 21:11) [40]


> Anatoly Podgoretsky ©   (14.10.11 21:06) [38]
> Это пример не профессионализма. Тупо сделаный код.

Собственно именно эту мысль я и попытался озвучить в первом посте :)



Страницы: 1 2 вся ветка

Форум: "Начинающим";
Текущий архив: 2012.02.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.004 c
2-1320135606
onyx2012
2011-11-01 11:20
2012.02.12
Фильтр в Express Quantum Grid


3-1271666302
fearless
2010-04-19 12:38
2012.02.12
Получить список компьютеров, подключенных к конкретной БД


2-1320485851
Артём
2011-11-05 12:37
2012.02.12
Переместить запись DbGrid


2-1320134437
Dennis I. Komarov
2011-11-01 11:00
2012.02.12
LogonUser


15-1319617616
oldman
2011-10-26 12:26
2012.02.12
А вы когда картошку жарите-варите, вы ее чистите?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский