Нечего сказать? Считаете окружающих недостаточно достойными, чтобы разжевывать азы?
Значит все таки хотите, что бы я АЗЫ разжевал.
Дело в том что в цепочке обработчиков общую скорость определяет самый медленный. Быстрее него вся цепочка работать не сможет.
А у нас такой случай сначала генерируются данные потом записываются в файл.
А если взять средства для замера производительности, то видно что самый медленный обработчик это генерация элемента матрицы.
Т.е. это наш случай, когда не стоит заниматься оптимизацией работы с файлами, а стоит заняться оптимизацией генерации данных.
Как бы вы не оптимизировали работу с файлами, но пока данные генерируются 2 часа. Программа будет работать 2 часа.
Пока мы не с генерируем порцию данные диск будет ждать.
Поэтому я и оптимизировал работу со строками время снизилось до 20 минут. Инструмент показал что операции стали соизмеримы. У уже только тогда я сделал оптимизацию записи.
Время снизилось до 10 минут. Но всё равно, диск работает 10% от своей скорости, так как вынужден ждать процессор.
И надо дальше оптимизировать генерацию данных. Но так как это модель и точный алгоритм генерации будет отличаться, то остановился на этом результате.
Код:
type
TIndexRec=packed record
FilePos:Int64;
Size:Int64;
i,j:Integer;
end;
TAIndexRec=array [0..0] of TIndexRec;
PAIndexRec=^TAIndexRec;
PIndexRec=^TIndexRec;
type
TFastString=record
Size:Integer;
str:String;
end;
procedure Add(var fs:TFastString; const s:String); overload;
var LenS:DWord;
begin
LenS:=Length(s);
if fs.Size+LenS>Length(fs.str) then
begin
SetLength(fs.str,Length(fs.str)*2);
end;
move(s[1],fs.str[fs.Size+1],LenS);
fs.Size:=fs.Size+LenS;
end;
procedure FastStringInit(var fs:TFastString; Size:Integer);
begin
fs.Size:=0;
SetLength(fs.str,Size);
end;
function GenStr(i:Integer):String;
var
k:Integer;
s0:String;
fs:TFastString;
begin
result := '';
FastStringInit(fs,1000*15);
for k:=1 to 1000 do
begin
s0 := intToStr(k*i); // имитируем вычисления элемента (i, j)
Add(fs,s0);
s0:=', ';
Add(fs,s0)
end;
result:=fs.str;
SetLength(result,Fs.Size);
end;
function IndexRec(FilePos:Int64; Size:Int64; i,j:Integer):TIndexRec;
begin
Result.FilePos:=FilePos;
Result.Size:=Size;
Result.i:=i;
Result.j:=j;
end;
procedure TForm1.Button2Click(Sender: TObject);
const
nm = 1000; // параметр масштаба
var
i,j : integer;
fp:Int64;
s,path:String;
fs:TFastString;
bdName,iName : string;
fbd,fi : File of byte;
t0,t1 : TDateTime;
IndexCashe:array [1..1000] of TIndexRec;
Size:Integer;
begin
path := extractFilePath (application.ExeName)+'tmp';
if not DirectoryExists(path) then
MkDir (path);
bdName:=path+'\Matrix.bd';
iName:=path+'\Matrix.i';
AssignFile(fbd,bdName);
AssignFile(fi,iName);
Rewrite(fbd);
Rewrite(fi);
t0 := now; // стартовое время
fp:=0;
FastStringInit(fs,1024*1024);
for i:=1 to nm do // для строк i
begin
for j:=1 to 1000 do // для столбца j
begin
s:=GenStr(i);
Add(fs,s);
IndexCashe[j]:=IndexRec(fp,Length(s),i,j);
Inc(fp,Length(s));
if fs.Size>$100000 then // 1 МБайт
begin
BlockWrite(fbd,fs.str[1],fs.Size*SizeOf(fs.str[1]));
fs.Size:=0;
end;
end;
BlockWrite(fi,IndexCashe[1],Length(IndexCashe)*SizeOf(IndexCashe[1]));
Caption := Format('%d',[i]); // Отображаем прогресс
end;
BlockWrite(fbd,fs.str[1],fs.Size*SizeOf(fs.str[1]));
closeFile(fbd);
closeFile(fi);
t1 := now;
Button2.Caption := 'Done';
Label1.Caption := ('test finished '+ FloatToStr(SecondSpan(t1,t0))+' sec.');
end;
Что касается сортировки, то я уже описал принципы и закодировал согласно им. Время работы составляет пару минут и упирается в жёсткий диск. Далее только диск менять или весь компьютер. Код не привожу, так как ещё надо доработать, протестировать и оформить должным образом.
Цитата:
И еще, я тут вспомнил, эффективнее всего писать данные блоками, равными блоку файловой системы.
Кратность блока может быть произвольным и почти не влияет на производительность. Т.е он может быть и не кратным.
Кратность была важна 20-40 лет назад, когда памяти было мало. А сейчас ОС кэширует данные и не тратиться на дополнительно чтение.
Вот если вы свой драйвер для жесткого диска пишете. о вам стоит подумать о кэширование. Просто по привычке используют степень кратную 2.
Цитата:
Ну и вообще имеет смысл погуглить что-нибудь про WinAPI и оптимизацию
Не имеет смысла. При больших блоках порядка 256,512 КБайт Write выдаёт 99% от скорости работы жёсткого диска. И доведя процент до 100% вы получите прирост 1.01 раза. Что соизмеримо с погрешностью измерения работы всей системы.
Вот если бы Write выдавал 50% тогда стоило задумываться.
Нет смысла оптимизировать скорость на десятки процентов. Так как эту разницу легко решить заменой комплектующих. А вот если надо ускориться в разы то тут стоит смотреть в сторону алгоритмов, а не WinAPI. Так как переход от O(n^2) к O(n) даст существенный выигрыш. Есть конечно трюки для ускорения в том числе и в разы.
В примере я отказался от Write в пользу BlockWrite только из за того что мне так захотелось, не более того.