Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.03.02;
Скачать: CL | DM;

Вниз

Чтение из 2-х гигового лога...   Найти похожие ветки 

 
Owa   (2008-02-04 23:24) [0]

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

Лог сервера. Лог текстовой с кодировкой юникод.

Я использую вот что:


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 гигов то процесс длится очень и очень долго. Есть-ли какой-то более быстрый метод для поиска в файле?
Спасибо.


 
Owa   (2008-02-04 23:25) [1]

Не то ткнул для выделения кода по запаре, простите..


 
DVM ©   (2008-02-04 23:48) [2]


> Application.ProcessMessages();

Убери. Либо быстро либо красиво.


> AnsiLowerCase(Edit1.Text)),

Зачем каждый виток цикла делать одно и то же - переводить в нижний регистр то, что можно перевести туда до цикла?


 
DVM ©   (2008-02-04 23:51) [3]

И может читать стоит более большими блоками, чем по одной строке?


 
palva ©   (2008-02-04 23:52) [4]

Ускорить можно, если читать не построчно, а большими блоками ну хотя бы килобайт по пятьсот. В блоке строки не выделять и не перекодировать, а искать сразу образец. Естественно, будет кропотливое программирование, чтобы отловить случаи, когда образец оказался разделен на части границей блока: можно, к примеру, читать блоки с небольшим перехлестом, длина которого будет равна максимальной длине строки. После нахождения образца нужно выделить всю строку перекодировать и добавить в STL.


 
ketmar ©   (2008-02-05 00:20) [5]

>[0] Owa (04.02.08 23:24)
а чо ищем-то? Boyer–Moore string search algorithm не пойдёт?


 
Amoeba ©   (2008-02-05 02:15) [6]

А может не грузить 2 гига в StringList (ЖУТЬ!!! Не дай Бог, чтобы такое приснилось), а использовать MemoryMapping и далее работать как с байтовым массивом-строкой?


 
Германн ©   (2008-02-05 02:21) [7]


> ketmar ©   (05.02.08 00:20) [5]
>
> >[0] Owa (04.02.08 23:24)
> а чо ищем-то? Boyer–Moore string search algorithm не пойдёт?
>
>

Ну если мне не изменяет мой склероз, то авторов там всё-таки трое. "Boyer-Moore-Horspool pattern searching algorithm".


 
ketmar ©   (2008-02-05 03:00) [8]

>[7] Германн ©(05.02.08 02:21)
таки двое. и завсегда было двое. параллельно с ними ещё кто-то то же придумал, и куча народу сочинила модификации.


 
ketmar ©   (2008-02-05 03:01) [9]

и процитировал я поисковую фразу для гугля. по которой сразу ныжные ссылочки даёт.


 
Slym ©   (2008-02-05 05:11) [10]

а так долго ищет?
" VBScript.
Option Explicit

if WScript.Arguments.Count() = 0 Then
 WScript.StdOut.WriteLine "No params"
 WScript.StdOut.WriteLine "cscript.exe cf.vbs filename"
 WScript.Quit()
End If

Dim RE,FSO,F
Set RE = New RegExp
RE.IgnoreCase = True
RE.Pattern = "String to find"
Set FSO = CreateObject("Scripting.FileSystemObject")
Set File= FSO.GetFile(WScript.Arguments(0))
WScript.StdOut.WriteLine ("Scan file: " + File.Path)
ScanFile File

Sub ScanFile(File)
 Dim InStream,OutStream, Line
 Set InStream = File.OpenAsTextStream
 Set OutStream = WScript.StdOut
 While Not InStream.AtEndOfStream
   Line = InStream.ReadLine
   If (Line<>"") and(RE.Test(Line)) Then
     OutStream.WriteLine(Line)
   End If
 WEnd
 InStream.Close()
 InStream=null
End Sub


 
хам   (2008-02-05 09:33) [11]

> [3] DVM ©   (04.02.08 23:51)
> И может читать стоит более большими блоками, чем по одной
> строке?

Это уже забота виндового кеша, а он, поверь, с ней справляется.


 
Skyle ©   (2008-02-05 10:29) [12]


> хам   (05.02.08 09:33) [11]
> > [3] DVM ©   (04.02.08 23:51)
> > И может читать стоит более большими блоками, чем по одной
>
> > строке?
>
> Это уже забота виндового кеша, а он, поверь, с ней справляется.
>

А мягкое всяко лучше красного. И вообще, это вам не громкое.


 
хам   (2008-02-05 10:42) [13]

> [12] Skyle ©   (05.02.08 10:29)
> А мягкое всяко лучше красного. И вообще, это вам не громкое.

Рад за тебя.


 
Skyle ©   (2008-02-05 11:01) [14]


> хам   (05.02.08 10:42) [13]
> > [12] Skyle ©   (05.02.08 10:29)
> > А мягкое всяко лучше красного. И вообще, это вам не громкое.
>
>
> Рад за тебя.

А я за тебя - нет.

Не надо считать, что оптимизация чтения с диска (виндовый кэш) и оптимизация обработки внутри программы - это одно и то же.


 
Игорь Шевченко ©   (2008-02-05 11:05) [15]

Skyle ©   (05.02.08 11:01) [14]

Не надо считать, что чтение большими блоками для ускорения чего-либо и геморрой с пересечением границ буферов есть оптимизация.

Впрочем, все в твоих руках - пишешь тест, читая readln и большими кусками, хронометрируешь, выкладываешь результаты вместе с кодом теста.


 
Skyle ©   (2008-02-05 11:11) [16]


> Игорь Шевченко ©   (05.02.08 11:05) [15]

Задача не моя, просто решил уточнить, что тут более одного этажа.


 
хам   (2008-02-05 11:13) [17]

> [14] Skyle ©   (05.02.08 11:01)
> Не надо считать, что оптимизация чтения с диска (виндовый
> кэш) и оптимизация обработки внутри программы - это одно
> и то же.

А чего, в [3] я где-то пропустил оптимизацию обработки? Да ито, что в [4] — тоже не оптимизация, а гемморой называется. Оптимизировать по идее нужно pos, но он всяко быстрее диска работает и так…


 
clickmaker ©   (2008-02-05 11:36) [18]


> Owa   (04.02.08 23:24)

RichEdit - плохой кандидат для 2-гиговых логов. Лучше уж просто Memo.
Либо замапить файл и рисовать текст самому - только видимую часть, с учетом прокрутки


 
хам   (2008-02-05 11:39) [19]

> [18] clickmaker ©   (05.02.08 11:36)
> RichEdit - плохой кандидат для 2-гиговых логов.

Любой компонент — любой кандидат для 2-гиговых логов. Пользователю за раз никогда не понадобится больше 100кб информации в одном контролле.


 
ANB   (2008-02-05 11:39) [20]


> Owa   (04.02.08 23:24)

1. Найти, что больше тормозит - чтение или поиск по строке.
Для этого  - закомментарить сравнение Поз и прогнать чисто чтение. Если будет так же медленно - то проблема в этом. ИМХО : реадлн - не самый шустрый способ прочитать файл.
2. Если будет летать - то оптимизить поиск по строке.


 
хам   (2008-02-05 11:41) [21]

> [20] ANB   (05.02.08 11:39)
> реадлн - не самый шустрый способ прочитать файл.

Я тебе так скажу: Прочитать файл с диска — не самый шустрый способ прочитьтать файл. А уж через что он читается, без раницы, все равно чтение с диска медленне копирования в оперативной памяти.


 
clickmaker ©   (2008-02-05 11:42) [22]


> Пользователю за раз никогда не понадобится больше 100кб
> информации в одном контролле.

не факт. Лично я сталкивался с ситуацией поиска в многометровом логе. Правда, я ничего для этого не писал, а юзал вьювер FAR"a )
В стандартные контролы только грузиться такой лог будет несколько минут (десятков секунд в лучшем случае)


 
palva ©   (2008-02-05 11:46) [23]

хам   (05.02.08 09:33) [11]
> Это уже забота виндового кеша, а он, поверь, с ней справляется.

Не понимаю о чем вы. Данные в сабже читаются однократно и не кэшируются. Может быть, вы надеетесь, что Windows будет буферизовать и читать данные большими блоками? Или компилятор делфи буферизует чтение данных? Ни то ни другое не происходит.
Вот если бы вы писали на си, вы действительно, не почувствовали бы особой разницы. В сишных библиотеках последовательный ввод данных буферизуется.


 
ANB   (2008-02-05 11:46) [24]


> хам   (05.02.08 11:41) [21]

Ща потестим . . .
ЗЫ. Кстати, при чтении большими блоками есть грабля из за юникодовой кодировки. Т.е. мона умудрится прочитать токо один байт двухбайтного символа.


 
хам   (2008-02-05 11:46) [25]

> [23] palva ©   (05.02.08 11:46)
> Может быть, вы надеетесь, что Windows будет буферизовать
> и читать данные большими блоками?

Я не надеюсь, я это точно знаю.


 
clickmaker ©   (2008-02-05 11:48) [26]


> ЗЫ. Кстати, при чтении большими блоками есть грабля из за
> юникодовой кодировки. Т.е. мона умудрится прочитать токо
> один байт двухбайтного символа.

для оптимального чтения размер блока должен быть кратен размеру кластера, т.е. минимум 512. По крайней мере, не должен быть нечетным


 
ANB   (2008-02-05 11:50) [27]

Милин. Делфи то нету пока :(
Попробовал фаром - файл 1 Гб, искал строку которой нет. Примерно 30 секунд. Т.е. быстрый способ есть :)


 
хам   (2008-02-05 11:52) [28]

> [26] clickmaker ©   (05.02.08 11:48)
> для оптимального чтения размер блока должен быть кратен
> размеру кластера, т.е. минимум 512.

Есть юникодовые кодировки с нефиксированным размером символа.


 
хам   (2008-02-05 11:52) [29]

> [26] clickmaker ©   (05.02.08 11:48)
> для оптимального чтения размер блока должен быть кратен
> размеру кластера, т.е. минимум 512.

Есть юникодовые кодировки с нефиксированным размером символа.


 
хам   (2008-02-05 11:53) [30]

> [27] ANB   (05.02.08 11:50)
> Попробовал фаром - файл 1 Гб, искал строку которой нет.
> Примерно 30 секунд.

1204/30 = 34 — примерно скорость линейного чтения современного жесткого диска.


 
palva ©   (2008-02-05 12:04) [31]


> пишешь тест, читая readln и большими кусками, хронометрируешь,
>  выкладываешь результаты вместе с кодом теста.

Заполнение большого файла 500000000 байт

{$APPTYPE CONSOLE}
var
 fo: textfile;
 i: Integer;
begin
 Assign(fo, "bigtest.txt");
 Rewrite(fo);
 for i:=1 to 10000000 do
   WriteLn(fo, "012345678901234567890123456789012345678901234567");
 closefile(fo);
end.

Построчное чтение

{$APPTYPE CONSOLE}
uses SysUtils;
var
 fo: textfile;
 i: Integer;
 s: string;
begin
 WriteLn(TimeToStr(now));
 Assign(fo, "bigtest.txt");
 Reset(fo);
 for i:=1 to 10000000 do begin
   ReadLn(fo, s);
   if pos(" ", s) > 0 then WriteLn("OK");
 end;
 closefile(fo);
 WriteLn(TimeToStr(now));
end.

11:42:18
11:42:45
27 секунд

Чтение большими блоками

{$APPTYPE CONSOLE}
uses SysUtils;
var
 fo: file;
 i: Integer;
 s: string;
begin
 WriteLn(TimeToStr(now));
 Assign(fo, "bigtest.txt");
 Reset(fo, 50000);
 SetLength(s, 50000);
 for i:=1 to 10000 do begin
   BlockRead(fo, s[1], 1);
   if pos(" ", s) > 0 then WriteLn("OK");
 end;
 WriteLn(TimeToStr(now));
 closefile(fo);
end.

11:52:03
11:52:11
8 секунд


 
palva ©   (2008-02-05 12:16) [32]


> хам   (05.02.08 11:46) [25]
> > [23] palva ©   (05.02.08 11:46)
> > Может быть, вы надеетесь, что Windows будет буферизовать
> > и читать данные большими блоками?

> Я не надеюсь, я это точно знаю.

Ну значит, вы неправы. Как и в том, что называете буферизацию кэшированием.


 
Slym ©   (2008-02-05 12:18) [33]

palva ©   (05.02.08 12:04) [31]
плохой тест... первое что бросилось - SetLength(s, 50000) - фиксированный буфер, а в первом варианте постоянно он пересоздается (ReadLn(fo, s);) а это утечка времени * 10млн - много


 
хам   (2008-02-05 12:20) [34]

первый вариант: 26 с, второй: 23 с. Хотя конечно, загрузка процессора меньше во втором случае ниже раза в 3-4.


 
ketmar ©   (2008-02-05 12:22) [35]

>[23] palva©(05.02.08 11:46)
>компилятор делфи буферизует чтение данных?

>В сишных библиотеках
как прикажешь понимать тебя, Саид?


>[30] хам (05.02.08 11:53)
FAR использует mmf и далеко не тупой strstr().


 
хам   (2008-02-05 12:23) [36]

ЗЫ. строку «if pos(" ", s) > 0 then WriteLn("OK");» упразднил, т.к. здесь у меня D7, а в D2006 она должны быть более быстрой за счет fastMM


 
Игорь Шевченко ©   (2008-02-05 12:24) [37]

palva ©   (05.02.08 12:04) [31]

У меня просьба - тесты местами поменяй ?

palva ©   (05.02.08 11:46) [23]


> Может быть, вы надеетесь, что Windows будет буферизовать
> и читать данные большими блоками?


Ага. Надеюсь. Более того, он это делает. Правда, "большой размер блока" - термин спорный, но несколько страниц за операцию чтения он читает.

"the Cache Manager reads further ahead for sequential access files--currently about three times more than files that are currently detected for sequential access. " (с) MSDN


 
Slym ©   (2008-02-05 12:24) [38]

на моем компе 8 секунд!:
program Project1;
{$APPTYPE CONSOLE}
uses SysUtils,Windows;
var
 t:DWord;
 s:string;
 i:integer;
begin
 t:=GetTickCount;
 for i:=1 to 10000000 do
 begin
   s:=FloatToStr(Random);
   if s="" then exit;
 end;
 writeln(FloatToStr((GetTickCount-t)/1000));
 readln;
end.


 
хам   (2008-02-05 12:24) [39]

> [37] Игорь Шевченко ©   (05.02.08 12:24)
> У меня просьба - тесты местами поменяй ?

Кстати, да :)


 
palva ©   (2008-02-05 13:14) [40]


> Игорь Шевченко ©   (05.02.08 12:24) [37]
> palva ©   (05.02.08 12:04) [31]
> У меня просьба - тесты местами поменяй ?

У меня обед кончился экспериментировать.
Если вы хотите, чтобы до нас дошла какая-то известная вам высокая истина, то вы выбрали не тот метод. Обсудите условия эксперимента, объясните подноготную, подготовьте и прогоните правильные с вашей точки зрения тесты выложите результаты - в общем, сделайте сами все то, что нам советуете. А ваш опыт и знания мы и так уважаем.

Если вернуться к сабжу, то чтение большими блоками, если говорить о программе на паскале, в разы ускоряет процесс.

> Slym ©   (05.02.08 12:18) [33]
> palva ©   (05.02.08 12:04) [31]
> плохой тест...

Ну это возможно. Напишите хороший тест или модифицируйте нужным образом мой. Возьмите к примеру второй мой тест и поменяйте коэффициент блокирования. Длину блока сделайте 50 и выложите результат. А я сейчас не могу этим заниматься.


 
Игорь Шевченко ©   (2008-02-05 13:16) [41]

palva ©   (05.02.08 13:14) [40]

Истина очень простая - после первого теста данные находятся в кэше Windows и во втором тесте они читаются несколько быстрее.


 
clickmaker ©   (2008-02-05 13:17) [42]


> то чтение большими блоками, если говорить о программе на
> паскале, в разы ускоряет процесс

не всегда.
сталкивался с ситуацией, когда чтение большими блоками с CD приводило к "запинанию" и тормозам. Возможно, это зависит от конкретного привода и болванки, но учитывать это тоже нужно


 
хам   (2008-02-05 13:18) [43]

> [40] palva ©   (05.02.08 13:14)
> Если вы хотите, чтобы до нас дошла какая-то известная вам
> высокая истина

Эта истина известна всем: виндовс кеширует и буферизирует чтение с диска.


 
palva ©   (2008-02-05 13:44) [44]


> Игорь Шевченко ©   (05.02.08 13:16) [41]
> palva ©   (05.02.08 13:14) [40]
> Истина очень простая - после первого теста данные находятся
> в кэше Windows и во втором тесте они читаются несколько
> быстрее.

В теории так и должно быть. Я потратил еще 5 минут, чтобы попробовать. Перед каждым тестом перезагружал машину (всю).
Второй тест:
13:23:12
13:23:24
Потом перезагрузился и запустил первый тест:
13:26.15
13:26.43


 
palva ©   (2008-02-05 13:46) [45]


> хам   (05.02.08 13:18) [43]

Кстати, какая у вас версия делфи. Я делал на 7.0.


 
хам   (2008-02-05 13:49) [46]

> [45] palva ©   (05.02.08 13:46)
> Кстати, какая у вас версия делфи. Я делал на 7.0.

Я тоже сделал на д7, но см [36].


 
хам   (2008-02-05 13:50) [47]

упраздил, конечно же, из обоих тестов :)


 
palva ©   (2008-02-05 13:56) [48]


> хам   (05.02.08 13:49) [46]
> но см [36].

Я смотрю ваше [34] и удивляюсь.


 
Anatoly Podgoretsky ©   (2008-02-05 14:44) [49]

Кроме указаных методов, серьезное ускорение можно получить при переходе на Юникод функции.
Ну и конечно MMF, но надо подумать над алгоритмами, что бы не получить обратное.


 
clickmaker ©   (2008-02-05 14:57) [50]

если запросить у MapViewOfFile сразу весь большой файл, можно получить отлуп по причине недостатка памяти.
Так что, там тоже блоками надо


 
DVM ©   (2008-02-05 15:11) [51]

MMF - не панацея. Распространенное заблуждение, что MMF поможет ускорить поиск в огромном файле.


 
хам   (2008-02-05 15:15) [52]

Что есть MMF то?


 
DVM ©   (2008-02-05 15:17) [53]


> хам   (05.02.08 15:15) [52]

Файлы отображенные в память


 
хам   (2008-02-05 15:19) [54]

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


 
DVM ©   (2008-02-05 15:20) [55]


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

Чтения с диска  - никак.


 
ketmar ©   (2008-02-05 15:30) [56]

>[51] DVM©(05.02.08 15:11)
таки поможет.


 
Игорь Шевченко ©   (2008-02-05 15:32) [57]

Мои исследования: (Сразу скажу, что 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

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


 
хам   (2008-02-05 15:36) [58]

Игорь, а какая версия дельфи?


 
DVM ©   (2008-02-05 15:36) [59]


> ketmar ©   (05.02.08 15:30) [56]


> таки поможет.

Как?


 
DVM ©   (2008-02-05 15:38) [60]


> Игорь Шевченко ©   (05.02.08 15:32) [57]

А я и не сомневался.


 
Игорь Шевченко ©   (2008-02-05 15:42) [61]

хам   (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.


Как видно, способ с отображением файла наиболее прост в коде :)


 
хам   (2008-02-05 15:48) [62]

> [61] Игорь Шевченко ©   (05.02.08 15:42)
> Как видно, способ с отображением файла наиболее прост в коде :)

Ага, пока Память приложения + размер файла < 2 гб.


 
ketmar ©   (2008-02-05 15:51) [63]

>[59] DVM©(05.02.08 15:36)
>Как?

убираются лишние гоняния данных по памяти.


 
Игорь Шевченко ©   (2008-02-05 15:52) [64]

хам   (05.02.08 15:48) [62]

Безусловно. Но цель ставилась оценить скорость чтения.


 
хам   (2008-02-05 15:58) [65]

> [64] Игорь Шевченко ©   (05.02.08 15:52)
> Но цель ставилась оценить скорость чтения.

Да я знаю :)


 
DVM ©   (2008-02-05 16:02) [66]


> ketmar ©   (05.02.08 15:51) [63]

Но на скорость чтения именно с диска это же не влияет. В любом случае читаем.


 
хам   (2008-02-05 16:02) [67]

> [63] ketmar ©   (05.02.08 15:51)
> убираются лишние гоняния данных по памяти.

Это все равно ничтожно мало по сравению с временем чтения диска, с ReadLn дело в чем-то другом, не знаю уж, как она изнутри сделана.


 
Игорь Шевченко ©   (2008-02-05 16:07) [68]

хам   (05.02.08 16:02) [67]


> с ReadLn дело в чем-то другом, не знаю уж, как она изнутри
> сделана.


Операций чтения (запросов к тому самому менеджеру кэша) в случае ReadLn гораздо больше. Мне самому стала интересна статистика именно ввода вывода


 
хам   (2008-02-05 16:10) [69]

> [68] Игорь Шевченко ©   (05.02.08 16:07)
> Операций чтения (запросов к тому самому менеджеру кэша)
> в случае ReadLn гораздо больше.

Ну не побайтово же она должна читать, в конце то концов :)


 
ANB   (2008-02-05 16:14) [70]


> Ну не побайтово же она должна читать, в конце то концов
> :)

Похоже, именно побайтово она и читает.


 
Игорь Шевченко ©   (2008-02-05 16:28) [71]

хам   (05.02.08 16:10) [69]


> Ну не побайтово же она должна читать, в конце то концов
> :)


По 128 байт она читает. То есть, на каждые 128 байт вызывается ReadFileA
Если воспользоваться калькулятором, то из
8351159 read IOs 1069023496 bytes read

как раз и получится 128 с очень небольшим хвостиком. Но это обращений к кэшу, а не к диску.
Получается проигрыш за счет лишних системных вызовов.


 
Leonid Troyanovsky ©   (2008-02-05 19:37) [72]


> 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.


 
palva ©   (2008-02-05 21:44) [73]

Попробовал компилятор 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
}



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

Текущий архив: 2008.03.02;
Скачать: CL | DM;

Наверх




Память: 0.68 MB
Время: 0.021 c
2-1202216049
saNat
2008-02-05 15:54
2008.03.02
Как установить тип курсора для всех элементов формы?


15-1200956475
Real
2008-01-22 02:01
2008.03.02
А зачем собственно USES в Delphi?


3-1192536774
Lamer666
2007-10-16 16:12
2008.03.02
ADOConnection плохо видит MsSql


15-1201366691
ZoldBerger
2008-01-26 19:58
2008.03.02
Исходники Delphi Decompiler а


15-1201497785
azamatufa
2008-01-28 08:23
2008.03.02
FireBird download files - что такое ...._pdb.zip ?