powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Список классов vs списка записей - в чем преимущество?
13 сообщений из 63, страница 3 из 3
Список классов vs списка записей - в чем преимущество?
    #39763723
Фотография Dimonka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гирлионайльдо,

Ну ландо, крутой массив. Осталось только обвязать его всем, чем положено: .Sort, .IndexOf, For in, копированием, владением объектами, совместимостью с TList итд и ВСЁ! можно использовать..
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763727
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
При вызове add от TList<Integer>

Он вызывает
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
function TListHelper.InternalAdd4(const Value): Integer;
begin
  InternalGrowCheck(FCount + 1);
  Result := FCount;
  PCardinal(FItems^)[FCount] := Cardinal(Value);
  Inc(FCount);
  FNotify(Value, cnAdded);
end;



Вызывает
Код: pascal
1.
2.
3.
4.
5.
6.
7.
procedure TListHelper.InternalGrowCheck(ANewCount: Integer);
begin
  if ANewCount > DynArraySize(FItems^) then
    InternalGrow(ANewCount)
  else if ANewCount < 0 then
    OutOfMemoryError;
end;



На функцию DynArraySize можно не обращать внимания, она inline
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
procedure TListHelper.InternalGrow(ANewCount: Integer);
var
  NewCount: Integer;
begin
  NewCount := DynArraySize(FItems^);
  if NewCount = 0 then
    NewCount := ANewCount
  else
    repeat
      NewCount := NewCount * 2;
      if NewCount < 0 then
        OutOfMemoryError;
    until NewCount >= ANewCount;
  InternalSetCapacity(NewCount);
end;



Код: pascal
1.
2.
3.
4.
procedure TListHelper.InternalSetCapacity(Value: NativeInt);
begin
  DynArraySetLength(FItems^, FTypeInfo, 1, @Value);
end;



Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
procedure DynArraySetLength(var a: Pointer; typeInfo: Pointer; dimCnt: NativeInt; lengthVec: PNativeInt);
var
  i,j: NativeInt;
  newLength, oldLength, minLength: NativeInt;
  elSize: NativeInt;
  t: PDynArrayTypeInfo;
  ElTypeInfo: Pointer;
  neededSize: NativeInt;
  p, pp: Pointer;
begin
  p := a;

  // Fetch the new length of the array in this dimension, and the old length
  newLength := lengthVec^;
  if newLength <= 0 then
  begin
    if newLength < 0 then
      Error(reRangeError);
    _DynArrayClear(a, typeInfo);
    exit;
  end;

  oldLength := 0;
  if p <> nil then
  begin
    Dec(PByte(p), SizeOf(TDynArrayRec));
    oldLength := PDynArrayRec(p).Length;
  end;

  // Calculate the needed size of the heap object
  t := PDynArrayTypeInfo( PByte(typeInfo) + PDynArrayTypeInfo(typeInfo).name );
  elSize := t.elSize;
  if t.elType <> nil then
    ElTypeInfo := t.elType^
  else
    ElTypeInfo := nil;
  neededSize := newLength*elSize;
  if neededSize div newLength <> elSize then
    Error(reRangeError);
  Inc(neededSize, SizeOf(TDynArrayRec));
  if neededSize < 0 then
    Error(reRangeError);

  // If the heap object isn't shared (ref count = 1), just resize it. Otherwise, we make a copy
  if (p = nil) or (PDynArrayRec(p).RefCnt = 1) then
  begin
    pp := p;
{$IF not Defined(WEAKREF)}
    if (newLength < oldLength) and (ElTypeInfo <> nil) then
      FinalizeArray(PByte(p) + SizeOf(TDynArrayRec) + newLength*elSize, ElTypeInfo, oldLength - newLength);
    ReallocMem(pp, neededSize);
{$ELSE}
    if (ElTypeInfo <> nil) then
    begin
      if SysHasWeakRef(PTypeInfo(ElTypeInfo)) then
      begin
        if newLength < oldLength then
          minLength := newLength
        else
          minLength := oldLength;
        GetMem(pp, neededSize);
        FillChar((PByte(pp) + SizeOf(TDynArrayRec))^, minLength * elSize, 0);
        if p <> nil then
        begin
          MoveArray(PByte(pp) + SizeOf(TDynArrayRec),
                     PByte(p) + SizeOf(TDynArrayRec), ElTypeInfo, minLength);
          if newLength < oldLength then
            FinalizeArray(PByte(p) + SizeOf(TDynArrayRec) + newLength*elSize, ElTypeInfo, oldLength - newLength);
          FreeMem(p);
        end;
      end
      else
      begin
        if (newLength < oldLength) then
          FinalizeArray(PByte(p) + SizeOf(TDynArrayRec) + newLength*elSize, ElTypeInfo, oldLength - newLength);
        ReallocMem(pp, neededSize);
      end;
    end
    else
      ReallocMem(pp, neededSize);
{$ENDIF}
    p := pp;
  end
  else
  begin
    GetMem(p, neededSize);
    minLength := oldLength;
    if minLength > newLength then
      minLength := newLength;
    if ElTypeInfo <> nil then
    begin
      FillChar((PByte(p) + SizeOf(TDynArrayRec))^, minLength*elSize, 0);
      __CopyArray(PByte(p) + SizeOf(TDynArrayRec), a, ElTypeInfo, minLength)
    end
    else
      Move(PByte(a)^, (PByte(p) + SizeOf(TDynArrayRec))^, minLength*elSize);
    _DynArrayClear(a, typeInfo);
  end;

  // The heap object will now have a ref count of 1 and the new length
  PDynArrayRec(p).RefCnt := 1;
  PDynArrayRec(p).Length := newLength;
  Inc(PByte(p), SizeOf(TDynArrayRec));

  // Set the new memory to all zero bits
  if newLength > oldLength then
    FillChar((PByte(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);

  // Take care of the inner dimensions, if any
  if dimCnt > 1 then
  begin
    Inc(lengthVec);
    Dec(dimCnt);
    i := 0;
    try
      while i < newLength do
        begin
          DynArraySetLength(PPointerArray(p)[i], ElTypeInfo, dimCnt, lengthVec);
          Inc(i);
        end;
    except
      // Free arrays on exception
      for j := 0 to i  do
        _DynArrayClear(PPointerArray(p)[j], ElTypeInfo);
      _DynArrayClear(p, typeInfo);
      raise;
    end;
  end;
  a := p;
end;

...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763731
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimonka,

Можно, но нужно ли? Всё же выигрыш в 0.3 - 0.4 сек не такой уж и важный
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763748
Фотография Dimonka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоDimonka,
Можно, но нужно ли? Всё же выигрыш в 0.3 - 0.4 сек не такой уж и важный
Так о чём и речь. Для каких-то специализированных целей можно ну очень специализированный список самому накалякать, а для универсального использования TList за глаза сойдёт.
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763873
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоНу и что бы закрепить, тест ещё на integer
0.968195
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
procedure Test;
var
  arr: TList<Integer>;
  i: Integer;
begin
  arr := TList<Integer>.Create;
  with arr do
  begin
    for i := 0 to 50000000 do
      add(i);
  end;
end;

Когда мой даёт 0.585812Давай, запили ещё тест, когда заполняются несколько листов одновременно.
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763879
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Bred eFeM
ГирлионайльдоНу и что бы закрепить, тест ещё на integer
0.968195
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
procedure Test;
var
  arr: TList<Integer>;
  i: Integer;
begin
  arr := TList<Integer>.Create;
  with arr do
  begin
    for i := 0 to 50000000 do
      add(i);
  end;
end;

Когда мой даёт 0.585812Давай, запили ещё тест, когда заполняются несколько листов одновременно.

Твой сарказм уже не уместен.

Могу привести, один важный факт.

Моя реализация, на 50000000 элементов, потребляет 197 озу.

Когда TList<Integer> потребляет на такое же количество, уже 262 озу

То есть, в 65 мб больше
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763894
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Твой сарказм уже не уместенпочему сарказм, интересно:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
program Project7;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  windows, System.SysUtils, System.Generics.Collections;

type
  PDynArrayRec = ^TDynArrayRec;

  TDynArrayRec = packed record
{$IFDEF CPU64BITS}
    _Padding: Integer; // Make 16 byte align for payload..
{$ENDIF}
    RefCnt: Integer;
    Length: NativeInt;
  end;

  ArrayEx<T> = record
    v: Pointer;
    CurrentLength, MaxLength: Integer;
    temp: TArray<T>;
    procedure add(Value: T);
    function GetIndex(i: Integer): T;
    function GetIndex2(i: Integer): T;
  end;

procedure ArrayEx<T>.add(Value: T);
type
  Test = array of T;
const
  elSize = SizeOf(Pointer);
  Plus = 48;
begin
  if MaxLength < CurrentLength then
  begin
    Inc(MaxLength, Plus);
    Dec(PByte(v), SizeOf(TDynArrayRec));
    v := SysReallocMem(v, MaxLength * elSize + SizeOf(TDynArrayRec));
    Inc(PByte(v), SizeOf(TDynArrayRec));
  end
  else if v = nil then
  begin
    MaxLength := Plus;
    v := SysGetMem(MaxLength * elSize + SizeOf(TDynArrayRec));
    Inc(PByte(v), SizeOf(TDynArrayRec));
  end;

  Test(v)[CurrentLength] := Value;

  Inc(CurrentLength);

  PPointer(@temp)^ := v;
  PDynArrayRec(NativeUInt(temp) - SizeOf(TDynArrayRec)).Length := CurrentLength;
end;

function ArrayEx<T>.GetIndex(i: Integer): T;
begin
  if (i >= MaxLength) and (i <= CurrentLength) then
    Result := GetIndex2(i);
end;

function ArrayEx<T>.GetIndex2(i: Integer): T;
type
  Test = array of T;
begin
  Result := Test(v)[i];
end;

function sprintf(S: PAnsiChar; const Format: PAnsiChar): Integer; cdecl;
  varargs; external 'msvcrt.dll';

function PrintTime(T: Int64): AnsiString;
var
  A, b: Int64;
begin
  Result := '';
  if QueryPerformanceCounter(A) and QueryPerformanceFrequency(b) then
  begin
    SetLength(Result, 25);
    SetLength(Result, sprintf(PAnsiChar(Result), '%f', single((A - T) / b)));
  end;
end;

const
  N = 250000; //
var
  arr: array [0..1023] of  ArrayEx<Integer>;
  arra:array [0..1023] of  TList<Integer>;
  i,j: Integer;
  T: Int64;
begin
  try
  QueryPerformanceCounter(T);
    for i := 0 to N do
      for j := Low(arr) to High(arr)
       do arr[j].add(i);
  Writeln('ArrayEx<Integer>.Add '+PrintTime(T));

  QueryPerformanceCounter(T);
    for j := Low(arr) to High(arr) do
     FreeMem(PByte(arr[j].v) - SizeOf(TDynArrayRec) );
  Writeln('ArrayEx<Integer>.Free '+PrintTime(T));

  //

  QueryPerformanceCounter(T);
    for j := Low(arra) to High(arra) do
     arra[j]:= TList<Integer>.Create;
    for i := 0 to N do
     for j := Low(arra) to High(arra) do
       arra[j].add(i);
  Writeln('TList<Integer>.Add '+PrintTime(T));

  QueryPerformanceCounter(T);
    for j := Low(arra) to High(arra) do
      FreeMem( PByte( PPointer(PByte(arra[j]) + 8 + SizeOf(TListHelper))^) - SizeOf(TDynArrayRec));
  Writeln('TList<Integer>."Free" '+PrintTime(T));

  //

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
// x86
// #1
ArrayEx<Integer>.Add 7.383058
ArrayEx<Integer>.Free 0.251668
TList<Integer>.Add 7.317250
TList<Integer>.Free 0.231141
// #2
ArrayEx<Integer>.Add 7.425692
ArrayEx<Integer>.Free 0.252234
TList<Integer>.Add 7.276288
TList<Integer>.Free 0.232548
// #3
ArrayEx<Integer>.Add 7.362651
ArrayEx<Integer>.Free 0.252028
TList<Integer>.Add 7.353942
TList<Integer>.Free 0.231327

// x64
// #1
ArrayEx<Integer>.Add 8.883673
ArrayEx<Integer>.Free 0.368604
TList<Integer>.Add 8.114259
TList<Integer>."Free" 0.237586
// #2
ArrayEx<Integer>.Add 8.921077
ArrayEx<Integer>.Free 0.367548
TList<Integer>.Add 8.247885
TList<Integer>."Free" 0.235625
// #3
ArrayEx<Integer>.Add 8.986561
ArrayEx<Integer>.Free 0.367565
TList<Integer>.Add 8.102526
TList<Integer>."Free" 0.236061
в чем сила, брат?
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763898
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Bred eFeM,

Доверяй, но проверяй :) У тебя проблема в циклах!


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
TList:
Init: 0.000154
Add: 4.669602
Free: 2.271111

TArrayEx:
Init: 0.000089
Add: 3.025231
Free: 0.143431



Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  windows, System.SysUtils, FastListArray, System.Generics.Collections;

function sprintf(S: PAnsiChar; const Format: PAnsiChar): Integer; cdecl;
  varargs; external 'msvcrt.dll';

function PrintTime(T: Int64): AnsiString;
var
  A, b: Int64;
begin
  Result := '';
  if QueryPerformanceCounter(A) and QueryPerformanceFrequency(b) then
  begin
    SetLength(Result, 25);
    SetLength(Result, sprintf(PAnsiChar(Result), '%f', single((A - T) / b)));
  end;
end;

procedure Start(func: Pointer);
var
  T: Int64;
type
  call = procedure();
begin
  QueryPerformanceCounter(T);
  call(func)();
  Writeln(PrintTime(T));
end;

const
  N = 250000; //

var
  arr: array [0 .. 1023] of TArrayEx<Integer>;
  arra: array [0 .. 1023] of TList<Integer>;
  i, j: Integer;
  T: Int64;

procedure TListTestInit;
begin
  for i := Low(arra) to High(arra) do
    arra[i] := TList<Integer>.Create;
end;

procedure TArrayExTestInit;
begin
  for i := Low(arr) to High(arr) do
    arr[i].init;
end;

procedure TListTestAdd;
begin
  for j := Low(arra) to High(arra) do
    for i := 0 to N do
      arra[j].add(i);
end;

procedure TArrayExTestAdd;
begin
  for j := Low(arr) to High(arr) do
    for i := 0 to N do
      arr[j].add(i);
end;

procedure TListTestFree;
begin
  for j := Low(arra) to High(arra) do
    arra[j].Free;
end;

procedure TArrayExTestFree;
begin
  for j := Low(arr) to High(arr) do
    arr[j].Free;
end;

begin
  try
    Writeln('TList: ');
    Writeln('Init: ');
    Start(@TListTestInit);

    Writeln('Add: ');
    Start(@TListTestAdd);

    Writeln('Free: ');
    Start(@TListTestFree);

    Writeln('TArrayEx: ');
    Writeln('Init: ');
    Start(@TArrayExTestInit);

    Writeln('Add: ');
    Start(@TArrayExTestAdd);

    Writeln('Free: ');
    Start(@TArrayExTestFree);

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;

end.

...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39763963
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоBred eFeM,

Доверяй, но проверяй :) У тебя проблема в циклах!эту проблему он кажется и тестит

Bred eFeMДавай, запили ещё тест, когда заполняются несколько листов одновременно.а не последовательно
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39764221
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоДоверяй, но проверяй :) У тебя проблема в циклах! о, спасибо, только это уже у тебя проблемы!
Код: pascal
1.
2.
3.
4.
5.
procedure TListTestFree; // Free*
begin
  for j := Low(arra) to High(arra) do
    FreeMem( PByte( PPointer(PByte(arra[j]) + 8 + SizeOf(TListHelper))^) - SizeOf(TDynArrayRec)); // => FreeMem (@TList<>.FList - SizeOf(TDynArrayRec))
end;

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
x86
TList:  #1          #2          #3
Init:   0.000174    0.000167    0.000175
Add:    3.298258    3.290902    3.280236
Free*:  0.206021    0.205084    0.205407
TArrayEx:
Init:   0.000058    0.000058    0.000064
Add:    3.951568    3.952066    3.951261
Free:   0.215579    0.215126    0.215459

x64
TList:  #1          #2          #3
Init:   0.000192    0.000182    0.000179
Add:    3.247844    3.236234    3.237612
Free*:  0.214759    0.220769    0.217551
TArrayEx:
Init:   0.000083    0.000089    0.000085
Add:    4.562433    4.430180    4.417473
Free:   0.362171    0.362515    0.363038

Если кроме твоего одного ArrayEx никто память не дёргает, то возможно это и быстрее, но в рабочем режиме частые реаллоки хуже, что мы и видим при тесте.
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39764284
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Bred eFeM,

Мне кажется ты врёшь с тестами
Нинадо так.

Я же сейчас протестировал на i3 и там тоже выигрыш как и на core 2 duo e8400.
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39764288
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тот код совершенно никак не может быть быстрее, по причине того, что там дёргается куча вызовов. А у меня в процедуре добавление только 1 проверка, которая срабатывает раз в год для того же SysReallocMem

По этому, делаю вывод что ты врунишка)
...
Рейтинг: 0 / 0
Список классов vs списка записей - в чем преимущество?
    #39764363
Bred eFeM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ГирлионайльдоТот код совершенно никак не может быть быстрее Ну, проси форумчан потестить - если истина дороже.

зы - i5-2400, Dx10.2.3
...
Рейтинг: 0 / 0
13 сообщений из 63, страница 3 из 3
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Список классов vs списка записей - в чем преимущество?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]