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

Вниз

Чтение из 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.67 MB
Время: 0.06 c
2-1202323170
ЗфдЗфднср
2008-02-06 21:39
2008.03.02
проблемка с Union All


2-1202463532
alexsashkan
2008-02-08 12:38
2008.03.02
Проблема с загрузкой из Екселя


2-1202062927
batya-x
2008-02-03 21:22
2008.03.02
TbitMap и function


3-1192554879
Игорь
2007-10-16 21:14
2008.03.02
есть база (Paradox) с полем BLOB типа


2-1202109520
Vasilii777
2008-02-04 10:18
2008.03.02
Помогите запросить Key!





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский