Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Чтение из 2-х гигового лога...


Страницы:   1 2 3 4

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]

Ну ясно. И как они могут увеличить скорость чтения с диска?


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо