Форум: "Начинающим";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];
ВнизКак сократить время выполнения процедуры? Найти похожие ветки
← →
Tatiana (2006-02-04 21:59) [0]Необходимо прочитать данные из *.txt файла. Данные структурированы. Проблема в том, что если количество строк большое (больше 10 000), то файл открывается недостаточно быстро. Каккие могут быть варианты, чтобы процедура выполнялась быстрее?
← →
HITMAN © (2006-02-04 22:14) [1]Попробуй в РичЕдит или процессор новый купи, побыстрее будет...
← →
homm © (2006-02-04 22:18) [2]
> Каккие могут быть варианты, чтобы процедура выполнялась
> быстрее?
Какая процедура? Вы не написали ничего конкретоного. Вым же нужно ускорить. А по сравнению с чем не написали.
> HITMAN © (04.02.06 22:14) [1]
На твою логику процесоров не напосешся.
← →
ПОМОГИТЕ (2006-02-04 22:37) [3]Мож он на агат ХР поставил, всё обгредил, а проц ещё слабый...
← →
Desdechado © (2006-02-04 22:51) [4]написать быструю процедуру
← →
PAVIA © (2006-02-05 02:56) [5]Чтобы было быстро нужно загрузить файл в памить и там его разбирать. Проще всего через потоки TStream +F1.
← →
Gero © (2006-02-05 03:05) [6]TStringList работает достаточно быстро.
← →
tesseract © (2006-02-05 15:43) [7]tatiana - Использовать ReadBuffer, а файл открывать, как бинарный с собственным разбором CR/LF.
← →
Desdechado © (2006-02-05 15:45) [8]> Данные структурированы
вот это самое интересное и самое неосвещенное место в вопросе.
и кода нет
гадаем дальше?
← →
Tatiana (2006-02-05 16:14) [9]подождите, не гадайте :) я как только смогу обязательно пошлю код и объясню подробнее.
← →
Anatoly Podgoretsky © (2006-02-05 16:45) [10]Объем менее одного мегабайта, любой метод загрузки будет мгновенный, хоть в StringList
← →
Tatiana (2006-02-05 20:52) [11]Структура строки в *.txt файле:
Name X Y Z Description,
где Name и Description – String, а X, Y, Z – числа, с которыми впоследствии будут производиться математические преобразования.
У меня есть три варианта процедуры чтения файла, но по времени выполнения они не отличаются.
procedure TPoints.ReadPoints(aFileName: String); var
j: integer;
s,St : String;
Point: RPoint;
F: TextFile;
begin
try
AssignFile(F, aFileName);
Reset(F);
While not(Eof(F)) do
begin
Readln(F, s);
s := TrimLeft(s);
s := TabToSpace(s);
s := DotToDecSep(s);
if s <> "" then
begin
St := "";
j := 1;
While s[j] <> " " do
begin
St := St + s[j];
j := j+1;
end;
Point.Name := St;
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While s[j] <> " " do
begin
St := St + s[j];
j := j+1;
end;
Point.X := StrToFloat(St);
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While s[j] <> " " do
begin
St := St + s[j];
j := j+1;
end;
Point.Y := StrToFloat(St);
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While s[j] <> " " do
begin
if j > Length(s) then Break;
St := St + s[j];
j := j+1;
end;
Point.Z := StrToFloat(St);
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While j <= Length(s) do
begin
St := St + s[j];
j := j+1;
end;
Point.Discription := St;
AddPoint(Point);
end;
end;
except on E:Exception do
DoOnError (peReadError) ;
end;
CloseFile(F);
end;
procedure TPoints.ReadPoints(aFileName: String); var
j, i: integer;
s,St : String;
Point: RPoint;
List: TStringList;
begin
try
List := TStringList.Create;
List.LoadFromFile(aFileName);
i := 0;
While i <= List.Count - 1 do
begin
s := List[i];
s := TrimLeft(s);
s := DotToDecSepSpace(s);
if s <> "" then
begin
St := "";
j := 1;
While s[j] <> " " do
begin
St := St + s[j];
j := j+1;
end;
Point.Name := St;
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While s[j] <> " " do
begin
St := St + s[j];
j := j+1;
end;
Point.X := StrToFloat(St);
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While s[j] <> " " do
begin
St := St + s[j];
j := j+1;
end;
Point.Y := StrToFloat(St);
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While s[j] <> " " do
begin
if j > Length(s) then Break;
St := St + s[j];
j := j+1;
end;
Point.Z := StrToFloat(St);
s := TrimLeft(RightStr(s, (Length(s)-Length(St))));
St := "";
j := 1;
While j <= Length(s) do
begin
St := St + s[j];
j := j+1;
end;
Point.Discription := St;
AddPoint(Point);
end;
i:= i + 1
end;
except on E:Exception do
DoOnError (peReadError) ;
end;
List.Free;
end;
procedure TPoints.ReadPoints(aFileName: String); var
i : integer;
s : String;
Point: RPoint;
List: TStringList;
begin
try
List := TStringList.Create;
List.LoadFromFile(aFileName);
i := 0;
While i <= List.Count - 1 do
begin
s := List[i];
s := Trim(s);
s := DotToDecSepSpace(s);
if s <> "" then
begin
Point.Name := LeftStr(s, Pos(" ", s) - 1);
s := TrimLeft(RightStr(s, (Length(s)-Pos(" ", s))));
Point.X := StrToFloat(LeftStr(s, Pos(" ", s) - 1));
s := TrimLeft(RightStr(s, (Length(s)-Pos(" ", s))));
Point.Y := StrToFloat(LeftStr(s, Pos(" ", s) - 1));
s := TrimLeft(RightStr(s, (Length(s)-Pos(" ", s))));
if Pos(" ", s) = 0 then
Point.Z := StrToFloat(s)
else
begin
Point.Z := StrToFloat(LeftStr(s, Pos(" ", s) - 1));
s := TrimLeft(RightStr(s, (Length(s)-Pos(" ", s))));
Point.Discription := s;
end;
AddPoint(Point);
end;
i:= i + 1
end;
except on E:Exception do
DoOnError (peReadError) ;
end;
List.Free;
end;
← →
Desdechado © (2006-02-05 21:17) [12]> Структура строки в *.txt файле:
не виду структуры, вижу только, что туда записано
структура подразумевает еще и "как записано"
т.е. должен быть указан формат, чем разделены поля, чем разделены строки, есть ли "шапка" и т.п.
← →
Tatiana (2006-02-05 21:35) [13]Файл заранее обработан таким образом, что в нем только цифры и , может быть слова (Name,Discriptoin), шапки нет, цифры (в смысле, поля) м.б. разделены пробелом, либо табуляцией, строки - вводом.
← →
Gero © (2006-02-05 22:01) [14]
procedure SplitString(const Str: string; Delimiter: Char; Strings: TStrings);
var
s: string;
Pos, Pos2: Integer;
begin
Strings.BeginUpdate;
try
Strings.Clear;
Pos := 1;
for Pos2 := 1 to Length(Str) do begin
if Str[Pos2] = Delimiter then begin
s := Copy(Str, Pos, Pos2 - Pos);
Strings.Add(s);
Pos := Pos2 + 1;
end;
end;
s := Copy(Str, Pos, Length(Str) - Pos + 1);
Strings.Add(s);
finally
Strings.EndUpdate;
end;
end;
(c) DMClient team
Функция заносит подстроки в строке, разделенные Delimiter в Strings.
Надеюсь, с чтением файла построчно проблем не возникнет.
← →
begin...end © (2006-02-05 22:09) [15]> Gero © (05.02.06 22:01) [14]
procedure SplitString(const Str: string; Delimiter: Char; Strings: TStrings);
begin
Strings.Delimiter := Delimiter;
Strings.DelimitedText := Str
end
← →
Gero © (2006-02-05 22:17) [16]> begin...end © (05.02.06 22:09)
Да, согласен, спасибо :)
Код старый и сюда был бездумно скопирован )
← →
Tatiana (2006-02-05 23:10) [17]Насколько я понимаю "." и "," тоже относятся к Delimiter? Если так, то процедура не подходит, т.к. в строке есть числа в виде десятичных дробей. Процедура SplitString отделит целые части от десятичных, а мне нужно все число. Я права???
← →
Gero © (2006-02-05 23:43) [18]> Насколько я понимаю "." и "," тоже относятся к Delimiter?
Delimiter передается аргументом в функцию и может быть каким угодно на твое усмотрение.
← →
Desdechado © (2006-02-06 10:52) [19]основное время уходит не на чтение из файла, а на операции по разрезанию строк
подозреваю, что количество табуляций/пробелов и прочего между числами плавающее (для визуального выравнивания в файле)
тогда нужно их позаменять на нормальный разделитель одного формата (например, табуляцию) StringReplace, а уж после этого применять SplitString
← →
Tatiana (2006-02-06 16:14) [20]Да, вы правы. Перед разделением строки я заменяю все разделители на пробелы, единственно, не меняю их количество, т.е. если было три табуляции, после выполнения функции они превращаются в три пробела.
← →
Tatiana (2006-02-08 16:57) [21]А кроме оптимизации кода, могут быть еще какие-нибудь варианты, чтобы заадча выполнялась быстрее. Дело в том, что ни один из вариантов, указанных выше, все равно по времени не отличается :(
← →
Alex_C © (2006-02-08 17:08) [22]Тебе уже ответили - тут выход один
ReadBlock и читать ну скачем по 64000 байта за раз.
Кстати недавно столкнулся с проблемой - надо было в базу переконвертировать текстовый фаил размером 19 мег. Так никакие TStringList.LoadFromFile и затем работа в памяти не помогли - очень долго, а вот читать как бинарный фаил блоками - наиболее быстро. Только по строкам прийдется тебе самому разбивать.
← →
vovnuke © (2006-02-08 17:15) [23]а что если с этой структурой работать с помощью ClientDataSet, а из него уже сохранять в файл?
← →
Tatiana (2006-02-09 00:21) [24]Проблема не в скачивании в память - это происходит быстро, а в разбиении строк.
procedure TPoints.ReadPoints(aFileName: String);
{ñ÷èòûâàåò äàííûå èç ôàéëà ñ èìåíåì aFileName â FStartPointsArr}
var
i : integer;
s : String;
Point: RPoint;
List: TStringList;
myStrings : TStringList;
begin
try
List := TStringList.Create;
myStrings := TStringList.Create;
List.LoadFromFile(aFileName);
i := 0;
While i <= List.Count - 1 do
begin
List[i] := TrimLeft(List[i]);
List[i] := DotToDecSepSpace(List[i]);
i := i + 1;
end;
{до этого места все идет достаточно быстро, а вот на нижеследующий цикл тратится слишком много времени. Может быть, я преувеличиваю, но если в *.txt файле около 17 000 строк (912KB), то программа его обрабатывает 5 минут. Ожидание кажется бесконечным...}
i := 0;
While i <= List.Count - 1 do
begin
s := List[i];
myStrings.Clear;
SplitString(s, " ", myStrings);
if s <> "" then
begin
Point.Name := myStrings[0];
Point.X := StrToFloat(myStrings[1]);
Point.Y := StrToFloat(myStrings[2]);
Point.Z := StrToFloat(myStrings[3]);
if myStrings.Count > 4 then
Point.Discription := myStrings[4];
end;
AddPoint(Point);
i:= i + 1
end;
except on E:Exception do
DoOnError (peReadError) ;
end;
List.Free;
myStrings.Free;
end;
← →
Defunct © (2006-02-09 03:59) [25]Tatiana (09.02.06 00:21) [24]
несущественное замечание: вместо while лучше использовать for.
существенное замечание: вместо SplitString для ускорения работы лучше единожды задать delimiter для myStrings, и просто менять DelimitedText (без очистки содержимого):
myStrings := TStringList.Create;
myStrings.Delimiter := " "; // <- единожды задать разделитель
...
with List do // для ускорения работы
for i := 0 to Count - 1 do // <-- вместо while
begin
/// myStrings.Clear; Выбросить
/// SplitString(..); Выбросить
S := Strings[i];
if S <> "" then
begin
myStrings.DelimitedText := S;
...
AddPoint(..); // ВНЕСТИ В ТЕЛО IF (иначе у вас некоторые записи будут дублироваться)
end
end
А также неплохо было бы привести код AddPoint,
для теста попробуйте вначале вообще ее (AddPoint) закоментировать.
← →
vovnuke © (2006-02-09 09:39) [26]2Tatiana
А тебе очень важно хранить данные именно в *.txt файле.
То работай со своими данными с использованием ClientDataSet, с ним будешь работать как с таблицей базы данных, сохраненной в файле.
Я думаю что загрузить из таблицы 17000 записей, будет побыстрее, чем из текстового файла 17000 строк.
← →
Tatiana (2006-02-09 11:11) [27]
> А тебе очень важно хранить данные именно в *.txt файле.
Лично мне все равно, но не я выбираю :(
← →
Gero © (2006-02-09 11:14) [28]> myStrings.Delimiter := " "; // <- единожды задать разделитель
Это лишнее.
← →
Leonid Troyanovsky © (2006-02-09 11:40) [29]
> Tatiana (09.02.06 00:21) [24]
> {до этого места все идет достаточно быстро, а вот на нижеследующий
> цикл тратится слишком много времени. Может быть, я преувеличиваю,
> но если в *.txt файле около 17 000 строк (912KB), то программа
> его обрабатывает 5 минут. Ожидание кажется бесконечным..
Подобные файлы на моем Celeron 2GHz 248M of RAM обрабатываются за 0.5 с
(файл 26М - 12 сек, 53М - 25 сек, 107М- 50 сек).
uses
Classes;
procedure TForm1.Button1Click(Sender: TObject);
var
fs: TFileStream;
p: TParser;
sl : Longint;
i: Longint;
f: array [0..2] of Extended;
n, s: String;
t : Cardinal;
begin
t := GetTickCount;
fx := 0;
fs := TFileStream.Create("file1.txt", fmOpenRead);
p := TParser.Create(fs);
while p.Token <> toEOF do
begin
sl := p.SourceLine;
if (p.Token = toSymbol) then // если имя - идентификатор паскаля
begin
n := p.TokenString;
s := "";
for i := 0 to 2 do
begin
p.NextToken;
p.CheckToken(toFloat); // если все числа в формате Float (with ".")
{см. также toInteger}
f[i] := p.TokenFloat;
end;
p.NextToken; // формируем Description
while (p.SourceLine = sl) and (p.Token <> toEOF) do
begin
s := s + " " + p.TokenString;
p.NextToken;
end;
{здесь записываем (обрабатываем) полученные значения}
end
else
p.NextToken;
end;
p.Free;
fs.Free;
ShowMessage(Format("%d",[GetTickCount-t]));
end;
Работа над ошибками оставлена в качестве домашнего задания.
--
Regards, LVT.
← →
Tatiana (2006-02-09 11:54) [30]
> Defunct © (09.02.06 03:59)
Вот это да!!! Действительно на AddPoint тратится все время....
procedure TPoints.AddPoint(Point: RPoint);
{существует класс, одним из полей является одномерный массив FPoints Arr, функция MCount текущую длину этого массива}
begin
SetLength(FPointsArr, MCount + 1);
FPointsArr[High(FPointsArr)] := Point;
end;
← →
Defunct © (2006-02-09 12:54) [31]Gero © (09.02.06 11:14) [28]
Почему? delimiter по-умолчанию не инициализируется значением " ".
Tatiana (09.02.06 11:54) [30]
> SetLength(FPointsArr, MCount + 1);
Вот здесь и тормоза. Изменение размера не маленького массива очень ресурсоемкая операция.
Думаю стоит задавать длину однократно. Вы точно знаете сколько строк прочитано сразу после загрузки файла в List. Вот и задайте массиву количество строк в качестве размера, перед заполением элементов. Далее просто считайте количество добавленных (реальных) элементов. После добавления всех элементов в массив - подкорректируйте его размер - подставьте в SetLength количество подсчитанных элементов.
← →
begin...end © (2006-02-09 13:10) [32]> Defunct © (09.02.06 03:59) [25]
> просто менять DelimitedText (без очистки содержимого)
Без очистки не получится, т.к. при изменении DelimitedText вызывается Clear.
> with List do // для ускорения работы
LOL
> Defunct © (09.02.06 12:54) [31]
> Почему? delimiter по-умолчанию не инициализируется значением " ".
with TStringList.Create do
try
DelimitedText := "abc def";
ShowMessage(IntToStr(Count))
finally
Free
end
Разгадка -- в коде TStrings.SetDelimitedText, вестимо.
← →
Defunct © (2006-02-09 15:25) [33]begin...end © (09.02.06 13:10) [32]
> Без очистки не получится, т.к. при изменении DelimitedText вызывается Clear.
Вдумчиво вчитайся в то, что было мной выброшено из кода. А именно был выброшен Clear.
>> with List do // для ускорения работы
> LOL
по словам Digitman, с with генерируемый код получается более эффективным. К тому же коментарий относится также и к for.
> Разгадка -- в коде TStrings.SetDelimitedText, вестимо.
что ж спасибо, хорошо, что всегда найдутся начитанные люди.
PS: что я и говорил ранее - желание "подклоть" так и прет.
← →
Gero © (2006-02-09 15:53) [34]> > Разгадка -- в коде TStrings.SetDelimitedText, вестимо.
> что ж спасибо, хорошо, что всегда найдутся начитанные люди.
>
> PS: что я и говорил ранее - желание "подклоть" так и прет.
Ты о чем? begin..end дал вполне конкретное объяснение, разгадка действительно в TStrings.SetDelimitedText.
← →
Defunct © (2006-02-09 16:01) [35]Gero © (09.02.06 15:53) [34]
Я о "LOL" и о первом предложении.
в том что begin...end дал верный ответ насчет SetDelimitedTest я не сомневаюсь, однако опять же тон каким этот ответ.
← →
begin...end © (2006-02-09 17:00) [36]> Defunct © (09.02.06 15:25) [33]
> Вдумчиво вчитайся в то, что было мной выброшено из кода.
> А именно был выброшен Clear.
Я читал. Только не понял, почему это было названо "существенным замечанием", а замена while на for -- "несущественным". Потому что на самом деле всё наоборот.
> с with генерируемый код получается более эффективным
По крайней мере, в данном случае он не получится более эффективным.
> PS: что я и говорил ранее - желание "подклоть" так и прет.
LOL. 3 раза.
← →
Defunct © (2006-02-09 17:27) [37]> Я читал.
А почему ж тогда написал: "Без очистки не получится, т.к. при изменении DelimitedText вызывается Clear."
>Только не понял, почему это было названо "существенным замечанием", а замена while на for -- "несущественным". Потому что на самом деле всё наоборот.
Если скажу честно, то все равно ведь не поверишь, и в очередной раз напишешь дурацкий lol. Оба замечания - несущественные, и на скорость практически не влияют, просто написав первое замечание, искал второе более существенное, но так и не найдя, забыл исправить слово "существенное" на "несущественное".
Фирштейн?
> По крайней мере, в данном случае он не получится более эффективным.
И это послужило поводом для LOL? над коментарием???
← →
begin...end © (2006-02-09 17:41) [38]> Defunct © (09.02.06 17:27) [37]
> А почему ж тогда написал: "Без очистки не получится, т.к.
> при изменении DelimitedText вызывается Clear."
Потому что без очистки действительно не получится.
> Оба замечания - несущественные, и на скорость практически
> не влияют
ОК, с этим могу согласиться. Но всё же, если сравнивать первое и второе замечания, первое действительно существеннее.
> просто написав первое замечание, искал второе более существенное,
> но так и не найдя, забыл исправить слово "существенное"
> на "несущественное".
Уфф, как сложно всё...
Действительно, верится с трудом.
:о)
> И это послужило поводом для LOL? над коментарием???
Конечно. Мне действительно было смешно, потому что ускорению работы кода за счёт with здесь просто неоткуда взяться.
← →
Defunct © (2006-02-09 17:47) [39]> Уфф, как сложно всё...
> Действительно, верится с трудом.
> :о)
Ну так, на самом деле так и есть :)
>> И это послужило поводом для LOL? над коментарием???
> Конечно. Мне действительно было смешно, потому что ускорению работы кода за счёт with здесь просто неоткуда взяться.
А если тоже самое прочесть не отрывая от следующего коментария, тоже будет смешно?
Что-то я не понимаю, проблему автора вопроса я локализовал, что еще от меня требуется? И почему я должен выслушивать насмешки?
← →
begin...end © (2006-02-09 17:55) [40]> Defunct © (09.02.06 17:47) [39]
> А если тоже самое прочесть не отрывая от следующего коментария,
> тоже будет смешно?
Да, тоже будет. Потому что про ускорение работы написано именно в строке с with. Значит, этот комментарий относится, по крайней мере, и к with тоже (если не только к нему). А это, как уже говорилось, смешно.
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2006.02.26;
Скачать: [xml.tar.bz2];
Память: 0.6 MB
Время: 0.04 c