![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Чтение из 2-х гигового лога...
Owa © (2008-02-04 23:24:00)Здравствуйте, хочу у вас поинтересоваться какой метод лучше применять для быстрого поиска в файле?
Лог сервера. Лог текстовой с кодировкой юникод.
Я использую вот что:
var
BaseItem : string;
F : textfile;
STL: TStringList;
begin
if key = VK_return then
begin
STL := TStringList.Create;
AssignFile(F, FP);
reset(f);
try
while not Eof(F) do
begin
Readln(F, BaseItem);
If pos(pchar(AnsiLowerCase(Edit1.Text)), pchar(AnsiLowerCase(BaseItem))) <>0 then
STL.Add(UTF8Decode(BaseItem));
Application.ProcessMessages();
end;
finally
CloseFile(F);
end;
RichEdit1.Lines.Text := STL.Text;
Application.ProcessMessages();
STL.Free;
end;
При маленьком объеме файла результат получается давольно быстро. А когда произвожу поиск в файле размером больше 2 гигов то процесс длится очень и очень долго. Есть-ли какой-то более быстрый метод для поиска в файле?
Спасибо.
palva (2008-02-05 21:44:00) [1]Попробовал компилятор Borland С++ 5.5. Только уже дома, на другом компьютере. Тесты дают одно и то же время - 9 секунд. Перезагрузку между тестами не делал.
#include <stdio.h>
#include <string.h>
#include <time>
FILE *fi;
int i;
char buf[51];
time_t t;
main() {
t = time(0);
buf[50] = 0;
fi = fopen("bigtest.txt", "rb");
for(i=0; i < 10000000; ++i) {
fread(buf, 50, 1, fi);
if(memchr(buf, '*', 50)) printf("%c\n", buf[0]);
}
fclose(fi);
printf("%d\n", time(0) - t); // выдает 9
}
#include <stdio.h>
#include <string.h>
#include <time>
FILE *fi;
int i;
time_t t;
char buf[50001];
main() {
t = time(0);
buf[50000] = 0;
fi = fopen("bigtest.txt", "rb");
for(i=0; i < 10000; ++i) {
fread(buf, 50000, 1, fi);
if(memchr(buf, '*', 50000)) printf("%c\n", buf[0]);
}
fclose(fi);
printf("%d\n", time(0) - t); // выдает 9
}
Leonid Troyanovsky (2008-02-05 19:37:00) [2]
> ketmar © (05.02.08 15:30) [56]
> таки поможет.
http://groups.google.com/group/fido7.su.win32.prog/msg/14bb69b4dec1da1a?dmode=source&output=gplain
http://groups.google.com/group/fido7.su.win32.prog/msg/e4edc3fb35401f38?dmode=source&output=gplain
Кодировка KOI8-R
--
Regards, LVT.
Игорь Шевченко (2008-02-05 16:28:00) [3]хам (05.02.08 16:10) [69]
> Ну не побайтово же она должна читать, в конце то концов
> :)
По 128 байт она читает. То есть, на каждые 128 байт вызывается ReadFileA
Если воспользоваться калькулятором, то из
8351159 read IOs 1069023496 bytes read
как раз и получится 128 с очень небольшим хвостиком. Но это обращений к кэшу, а не к диску.
Получается проигрыш за счет лишних системных вызовов.
ANB (2008-02-05 16:14:00) [4]
> Ну не побайтово же она должна читать, в конце то концов
> :)
Похоже, именно побайтово она и читает.
хам (2008-02-05 16:10:00) [5]> [68] Игорь Шевченко © (05.02.08 16:07)
> Операций чтения (запросов к тому самому менеджеру кэша)
> в случае ReadLn гораздо больше.
Ну не побайтово же она должна читать, в конце то концов :)
Игорь Шевченко (2008-02-05 16:07:00) [6]хам (05.02.08 16:02) [67]
> с ReadLn дело в чем-то другом, не знаю уж, как она изнутри
> сделана.
Операций чтения (запросов к тому самому менеджеру кэша) в случае ReadLn гораздо больше. Мне самому стала интересна статистика именно ввода вывода
хам (2008-02-05 16:02:00) [7]> [63] ketmar © (05.02.08 15:51)
> убираются лишние гоняния данных по памяти.
Это все равно ничтожно мало по сравению с временем чтения диска, с ReadLn дело в чем-то другом, не знаю уж, как она изнутри сделана.
DVM (2008-02-05 16:02:00) [8]
> ketmar © (05.02.08 15:51) [63]
Но на скорость чтения именно с диска это же не влияет. В любом случае читаем.
хам (2008-02-05 15:58:00) [9]> [64] Игорь Шевченко © (05.02.08 15:52)
> Но цель ставилась оценить скорость чтения.
Да я знаю :)
Игорь Шевченко (2008-02-05 15:52:00) [10]хам (05.02.08 15:48) [62]
Безусловно. Но цель ставилась оценить скорость чтения.
ketmar (2008-02-05 15:51:00) [11]>[59] DVM©(05.02.08 15:36)
>Как?
убираются лишние гоняния данных по памяти.
хам (2008-02-05 15:48:00) [12]> [61] Игорь Шевченко © (05.02.08 15:42)
> Как видно, способ с отображением файла наиболее прост в коде :)
Ага, пока Память приложения + размер файла < 2 гб.
Игорь Шевченко (2008-02-05 15:42:00) [13]хам (05.02.08 15:36) [58]
2006
Соответственно, сделан еще один тест, через отображение в память
Elapsed: 00:00:04 95103772
1 read IOs 52958 bytes read
Читается весь файл, операции ввода-вывода здесь совершенно не учитываются, так что строчка просто скопирована :)
Код:
program ReadTest;
{$APPTYPE CONSOLE}
uses
SysUtils,
Main in 'Main.pas';
begin
if ParamCount >= 1 then
if UpperCase(Copy(ParamStr(1),1,2)) = '-B' then
ReadBlock
else if UpperCase(Copy(ParamStr(1),1,2)) = '-M' then
ReadMap
else
ReadLine;
end.
unit Main;
interface
procedure ReadBlock;
procedure ReadLine;
procedure ReadMap;
implementation
uses
SysUtils, Windows, HsFileMapper;
var
StartTime: TDateTime;
type
IO_COUNTERS = packed record
ReadOperationCount: LARGE_INTEGER;
WriteOperationCount: LARGE_INTEGER;
OtherOperationCount: LARGE_INTEGER;
ReadTransferCount: LARGE_INTEGER;
WriteTransferCount: LARGE_INTEGER;
OtherTransferCount: LARGE_INTEGER;
end;
PIO_COUNTERS = ^IO_COUNTERS;
function GetProcessIoCounters(Process: THandle; Ios: PIO_COUNTERS): Boolean;
stdcall; external 'Kernel32.dll';
procedure PrintIos;
var
Ios: IO_COUNTERS;
begin
if GetProcessIoCounters(GetCurrentProcess(), @Ios) then
writeln(IntToStr(Ios.ReadOperationCount.QuadPart), ' read IOs ',
IntToStr(Ios.ReadTransferCount.QuadPart), ' bytes read');
end;
procedure ReadBlock;
var
fo: file;
i, j: Integer;
s: string;
begin
StartTime := Now;
Assign(fo, 'c:\files\bigtest.txt');
Reset(fo, 50000);
SetLength(s, 50000);
I := 0;
while not Eof(fo) do begin
BlockRead(fo, s[1], 1);
for j := 1 to Length(S) do
if s[J] = ' ' then
Inc(I);
end;
closefile(fo);
WriteLn('Elapsed: '+FormatDateTime('hh:nn:ss', now-StartTime), ' ', i);
printios;
end;
procedure ReadLine;
var
fo: textfile;
i, j: Integer;
s: string;
begin
StartTime := Now;
Assign(fo, 'c:\files\bigtest.txt');
Reset(fo);
I := 0;
while not eof(fo) do begin
ReadLn(fo, s);
for j := 1 to Length(S) do
if s[J] = ' ' then
Inc(I);
end;
closefile(fo);
WriteLn('Elapsed: '+FormatDateTime('hh:nn:ss', now-StartTime), ' ', i);
printios;
end;
procedure ReadMap;
var
Mapper: THSFileMapper;
P: PChar;
I, J: Integer;
begin
StartTime := Now;
Mapper := THSFileMapper.Create('c:\files\bigtest.txt');
try
P := Mapper.Map;
I := 0;
for J := 0 to Mapper.FileSize - 1 do
begin
if P^ = ' ' then
Inc(I);
Inc(P);
end;
finally
Mapper.Free;
end;
WriteLn('Elapsed: '+FormatDateTime('hh:nn:ss', now-StartTime), ' ', i);
printios;
end;
end.
{
Модуль: HSFileMapper
Описание: Класс, обеспечиващий создание файла, проецируемого в память
Автор: Игорь Шевченко
Дата создания: 07.02.2003
История изменений:
}
unit HsFileMapper;
{$I HsCommon.Inc}
{$IFDEF _D6}
{$WARN SYMBOL_PLATFORM OFF}
{$WARN SYMBOL_DEPRECATED OFF}
{$ENDIF}
interface
uses
Windows;
type
THSFileMapper = class
private
FFileHandle: THandle;
FFileSize: DWORD;
FMap: PChar;
FFileName: string;
function GetEndMap: PChar;
public
constructor Create (const AFileName: string);
destructor Destroy; override;
property Map: PChar read FMap;
property EndMap: PChar read GetEndMap;
property FileSize: DWORD read FFileSize;
property FileName: string read FFileName;
end;
implementation
uses
SysUtils;
{ THSFileMapper }
constructor THSFileMapper.Create(const AFileName: string);
var
SizeHighPart: DWORD;
FileMapping: THandle;
begin
FFileName := AFileName;
FFileHandle := CreateFile (PChar(AFileName), GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if FFileHandle = INVALID_HANDLE_VALUE then
RaiseLastWin32Error;
FFileSize := GetFileSize(FFileHandle, @SizeHighPart);
FileMapping := CreateFileMapping (FFileHandle, nil, PAGE_READONLY, 0, 0, nil );
if FileMapping = 0 then
RaiseLastWin32Error;
FMap := MapViewOfFile (FileMapping, FILE_MAP_READ, 0, 0, 0 );
CloseHandle (FileMapping);
if not Assigned(FMap) then
RaiseLastWin32Error;
end;
destructor THSFileMapper.Destroy;
begin
if Assigned(FMap) then
UnmapViewOfFile (FMap);
if FFileHandle <> INVALID_HANDLE_VALUE then
CloseHandle (FFileHandle);
inherited;
end;
function THSFileMapper.GetEndMap: PChar;
begin
Result := FMap + FFileSize;
end;
end.
Как видно, способ с отображением файла наиболее прост в коде :)
DVM (2008-02-05 15:38:00) [14]
> Игорь Шевченко © (05.02.08 15:32) [57]
А я и не сомневался.
DVM (2008-02-05 15:36:00) [15]
> ketmar © (05.02.08 15:30) [56]
> таки поможет.
Как?
хам (2008-02-05 15:36:00) [16]Игорь, а какая версия дельфи?
Игорь Шевченко (2008-02-05 15:32:00) [17]Мои исследования: (Сразу скажу, что palva прав)
program ReadTest;
{$APPTYPE CONSOLE}
uses
SysUtils,
Main in 'Main.pas';
begin
if ParamCount >= 1 then
if UpperCase(Copy(ParamStr(1),1,2)) = '-B' then
ReadBlock
else
ReadLine;
end.
unit Main;
interface
procedure ReadBlock;
procedure ReadLine;
implementation
uses
SysUtils, Windows;
var
StartTime: TDateTime;
type
IO_COUNTERS = packed record
ReadOperationCount: LARGE_INTEGER;
WriteOperationCount: LARGE_INTEGER;
OtherOperationCount: LARGE_INTEGER;
ReadTransferCount: LARGE_INTEGER;
WriteTransferCount: LARGE_INTEGER;
OtherTransferCount: LARGE_INTEGER;
end;
PIO_COUNTERS = ^IO_COUNTERS;
function GetProcessIoCounters(Process: THandle; Ios: PIO_COUNTERS): Boolean;
stdcall; external 'Kernel32.dll';
procedure PrintIos;
var
Ios: IO_COUNTERS;
begin
if GetProcessIoCounters(GetCurrentProcess(), @Ios) then
writeln(IntToStr(Ios.ReadOperationCount.QuadPart), ' read IOs ',
IntToStr(Ios.ReadTransferCount.QuadPart), ' bytes read');
end;
procedure ReadBlock;
var
fo: file;
i, j: Integer;
s: string;
begin
StartTime := Now;
Assign(fo, 'c:\files\bigtest.txt');
Reset(fo, 50000);
SetLength(s, 50000);
I := 0;
while not Eof(fo) do begin
BlockRead(fo, s[1], 1);
for j := 1 to Length(S) do
if s[J] = ' ' then
Inc(I);
end;
closefile(fo);
WriteLn('Elapsed: '+FormatDateTime('hh:nn:ss', now-StartTime), ' ', i);
printios;
end;
procedure ReadLine;
var
fo: textfile;
i, j: Integer;
s: string;
begin
StartTime := Now;
Assign(fo, 'c:\files\bigtest.txt');
Reset(fo);
I := 0;
while not eof(fo) do begin
ReadLn(fo, s);
for j := 1 to Length(S) do
if s[J] = ' ' then
Inc(I);
end;
closefile(fo);
WriteLn('Elapsed: '+FormatDateTime('hh:nn:ss', now-StartTime), ' ', i);
printios;
end;
end.
Результат построчного чтения:
Elapsed: 00:00:34 95103772 пробелов
8351152 read IOs 1069000094 bytes read
Результат поблочного чтения:
Elapsed: 00:00:04 95099921
21379 read IOs 1068952958 bytes read
Видно, что поблочное чтение читает не весь файл, но разницей в данном случае можно пренебречь.
Файл, соответственно, гигабайтный
ketmar (2008-02-05 15:30:00) [18]>[51] DVM©(05.02.08 15:11)
таки поможет.
DVM (2008-02-05 15:20:00) [19]
> И как они могут увеличить скорость чтения с диска?
Чтения с диска - никак.
хам (2008-02-05 15:19:00) [20]Ну ясно. И как они могут увеличить скорость чтения с диска?