Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ускорение работы с динамическими массивами


Страницы:   1 2 3 4

alertus ©   (2005-05-24 16:40:00) 

Добрый день, подскажите, пожалуйста, что делать.
Я написал довольно сложный алгоритм (моделирование и обучение нейронных сетей). Все восхитительно работает, но медленно :((

Написал несколько классов для работы с матрицами, нейронными слоями и нейронными сетями, там все построено на динамических массивов real.

Я делаю это так:
var
 a:array of array of real; //матрица
const
 w = 10; //ширина
 h = 5;  //высота
.....
Initialize(a);
SetLength(a,w*h);
i:=2; //столбец
j:=4; //строка
a[j+(i-1)*w]:=0.5; //установим елемент
Finalize(a);


Ну и т.п. все это забито в методы, например
TMatrix.SetElem(i,j:integer;r:real);

Я знаю, что с динамическими массивами можно еще работать так:
type
 myarray = array[1..1000] of real;
 pmyarray = ^myarray;
var
 a:pmyarray;
const
 w = 10;
 h = 5;
.....
i:=2;
j:=4;
getmem(a,w*h*sizeof(real));
a^[j+(i-1)*w]:=0.5;
freemem(a);


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

Подскажите, пожалуйста, кто сталкивался с подобными вопросами.
Может быть вообще скорость теряется не на динамических массивах, а на многочисленных арифметический операциях, как тогда ускорить их, я уже подумал о
asm
end;


alertus   (2005-05-25 19:22:00) [21]

Я сравниваю скорость по этому фрагменту:
edit1.text:=timetostr(time);
for i:=1 to 1000000000 do begin
  for j:=0 to 9 do begin
    c[j]:=a[j]*b[j];
  end;
end;
edit2.text:=timetostr(time);

И он отличается минимум в 2 раза.


Mx   (2005-05-25 19:17:00) [22]


> alertus   (25.05.05 19:02) [53]

Насчет примера: Initialize вызывать не надо. Если ты сравниваешь скорость всей ButtonXClick, то возможно ее съедает SetLength, но доступ по скорости не может отличаться.


> Кстати, если я правильно понял, то и в окне CPU видно, что
> программа обращается к memo1.Lines.Count каждый раз

Естественно! Каждый раз в цикле по I, но не по J.


alertus   (2005-05-25 19:16:00) [23]

Да, не могу не согласиться, тут я неправ.
Но если присутствуют именно такие вложенные циклы, то второй код выгоднее.


begin...end   (2005-05-25 19:13:00) [24]

> alertus   (25.05.05 19:02) [53]

> for i:=1 to 1000000 do begin
>    for j:=1 to memo1.Lines.Count do begin
>    end;
>  end;

Здесь на каждом проходе цикла по i выполняется вход в цикл по j. Поэтому совершенно нормально и логично, что на каждой итерации цикла по iвычисляется конечное значение счётчика цикла по j. Это не опровергает вышесказанного, т.к. на каждой итерации цикла по jобращения к Lines.Count не происходит.

Измените пример так:

for i:=1 to memo1.Lines.Count do begin
  for j:=1 to 1000000 do begin
  end;
end

и удивитесь результату.


alertus   (2005-05-25 19:08:00) [25]


> Код проверки можно увидеть?

Для динамического:
procedure TForm1.Button1Click(Sender: TObject);
var
 a:array of real;
 b:array of real;
 c:array of real;
 i,j:integer;
begin
 Initialize(a);
 Initialize(b);
 Initialize(c);
 SetLength(a,10);
 SetLength(b,10);
 SetLength(c,10);
 for i:=0 to 9 do begin
   a[i]:=i;
   b[i]:=9-i;
 end;
 edit1.text:=timetostr(time);
 for i:=1 to 1000000000 do begin
   for j:=0 to 9 do begin
     c[j]:=a[j]*b[j];
   end;
 end;
 edit2.text:=timetostr(time);
 finalize(a);
 finalize(b);
 finalize(c);
end;


Для статического:
procedure TForm1.Button2Click(Sender: TObject);
var
 a:array[0..9] of real;
 b:array[0..9] of real;
 c:array[0..9] of real;
 i,j:integer;
begin
 for i:=0 to 9 do begin
   a[i]:=i;
   b[i]:=9-i;
 end;
 edit1.text:=timetostr(time);
 for i:=1 to 1000000000 do begin
   for j:=0 to 9 do begin
     c[j]:=a[j]*b[j];
   end;
 end;
 edit2.text:=timetostr(time);
end;


alertus   (2005-05-25 19:02:00) [26]

Может я чего-то не понимаю, но такой код:
edit1.Text:=timetostr(time);
 f:=memo1.Lines.Count;
 for i:=1 to 1000000 do begin
   for j:=1 to f do begin
   end;
 end;
 edit2.Text:=timetostr(time);


работает намного быстрее, чем
edit1.Text:=timetostr(time);
 for i:=1 to 1000000 do begin
   for j:=1 to memo1.Lines.Count do begin
   end;
 end;
 edit2.Text:=timetostr(time);


Кстати, если я правильно понял, то и в окне CPU видно, что программа обращается к memo1.Lines.Count каждый раз.


begin...end   (2005-05-25 19:02:00) [27]

> alertus   (25.05.05 19:00) [51]

Код проверки можно увидеть?


alertus   (2005-05-25 19:00:00) [28]


> Повторю: если речь идёт о скорости доступа к элементу, то
> такого не может быть.

А какое может быть??

Я проверял так:
беру три масива (сначала динамических, а потом статических),
пробегаю по ним циклом, записывая в третий произведения первого и второго (поэлементно), результат -- в три раза быстрее...


begin...end   (2005-05-25 18:57:00) [29]

> Mx ©   (25.05.05 18:25) [48]

> Насчет скорости при выделении, думаю лучше использовать
> то, что сама Borland рекомендует (SetLength), а то вдруг
> че-нить поменяют?

Я и не предлагаю использовать GetMem для динамических массивов. Я говорил про использование GetMem для типов-указателей на статический массив. И имел в виду, что выделение одного и того же объёма памяти для соответствующихтипов этими двумя способами сильно различается по скорости.

> alertus   (25.05.05 18:47) [49]

> Кстати, статитические массивы примерно в 3 раза быстрее
> работают, сегодня проверял.

Повторю: если речь идёт о скорости доступа к элементу, то такого не может быть.


alertus   (2005-05-25 18:47:00) [30]


> Var - там ссылка в любом случае. Однако все зависит от задачи.
> Если в процедуре ты не планируешь изменение размера массива,
> то, в моем понимании, лучше через const.

Нет, я изменяю только элементы массива.
Вообще все массивы создаются один раз и больше не изменяются, динамические же они потому, что это универсальный Unit, который поддержывает сети с произвольным количеством слоев, нейронов и т.д.
Так что можно сказать, что массивы статические для данной программы, но для Unit'a они динамические...
Кстати, статитические массивы примерно в 3 раза быстрее работают, сегодня проверял.
Мне же надо разогнать в 5-6 раз (именно во столько раз медленнее работает, чем аналогичные программы в Matlab)


> А что ты делаещь с нейронной сетью. Оч оптимальное решение
> - упростить её.

В том то и дело, что заранее не известно, что будет делать сеть, она универсальная...


Mx   (2005-05-25 18:25:00) [31]


> begin...end ©

В тот раз обсуждали именно доступ, про него и написал. Насчет скорости при выделении, думаю лучше использовать то, что сама Borland рекомендует (SetLength), а то вдруг че-нить поменяют?


> alertus
> Все таки интересно, как лучше написать

Без разницы. В любом случае Lines.Count вычислится только один раз. Теоритечески даже медленее второй вариант, так как включает присвоение переменной.


> поверил на слово

Как недавно выснилось, не всему из того, что там написано надо верить.


> как быстрее - var, const или без всего

Var - там ссылка в любом случае. Однако все зависит от задачи. Если в процедуре ты не планируешь изменение размера массива, то, в моем понимании, лучше через const.


Kolan   (2005-05-25 16:50:00) [32]

А что ты делаещь с нейронной сетью. Оч оптимальное решение - упростить её.


TUser   (2005-05-25 16:23:00) [33]

С динамическими массивами лучше работать примерно так
var A: array of integer;
   ACount: integer;

// добавление элемента
if ACount = length(A) then
 SetLength(A, ACount+256);
A[ACount]:=Value;
inc (ACount);

И еще - если есть возмолжность замени все на целочисленную арифметику. Эти два примеа позволят разогнаться раза в 2-5.


evvcom   (2005-05-25 16:15:00) [34]


> И почему же, позволь полюбопытствовать?

Согласен. Вспомнил какую-то статью, не проверив. Без разницы. Компилятор единожды вычисляет .lines.count – 1, а потом только dec(i) выполняет.


begin...end   (2005-05-25 16:05:00) [35]

> alertus   (25.05.05 12:42) [42]

> Мне не особо важна скорость выдеоления памяти, а вот скорость
> доступа к элементам -- важна.

Про скорость доступа я уже говорил. Вряд ли удастся её увеличить. Единственное, что можно делать -- это следить за оптимальностью вычисления самих индексов (в смысле, не вычислять их без необходимости).

> я прочитал таки статью

Таки зачем?

> evvcom ©   (25.05.05 15:54) [43]

> lin := .lines.count – 1;
> for i:=0 to lin do...
> быстрее

И почему же, позволь полюбопытствовать?


evvcom   (2005-05-25 15:54:00) [36]

Как быстрее можно понять из CPU Window. Var и Const - одинаково, а без всего - в зависимости от длины данных: до 4 байт включительно - так же, более 4-х дольше, и чем длиннее, тем дольше, так как делается копия данных в стеке.

lin := .lines.count – 1;
for i:=0 to lin do...

быстрее


alertus   (2005-05-25 12:42:00) [37]

Мне не особо важна скорость выдеоления памяти, а вот скорость доступа к элементам -- важна.
А как насчет передачи параметров в функцию, как быстрее - var, const или без всего (value)??

А еще вопрос такой: я прочитал таки статью http://www.delphimaster.ru/articles/optimization.html
и поверил на слово.

Все таки интересно, как лучше написать:
for i:=0 to memo1.lines.count – 1 do...
или
lin := .lines.count – 1;
for i:=0 to lin do...


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


begin...end   (2005-05-25 11:15:00) [38]

> Mx ©   (25.05.05 10:58) [40]

Нет, выделение памяти через GetMem как раз намного быстрее выделения такого же объёма через SetLength.
А вот скорость доступа к элементу массива будет практически такой же, о чём я и сказал в [1].


Mx   (2005-05-25 10:58:00) [39]

Если ты имеешь ввиду разницу в скорости работы через GetMem или SetLenght, то это уже обсуждалось, разницы никакой.


alertus   (2005-05-25 10:36:00) [40]

А какой вывод из этого всего можно сделать, как быстрее работать будет.
Я так понимаю, динамический массив всегда по ссылке передается, потому что передается не сам массив данных, а только адрес первого элемента и функция уже производит действия с елементами, расположенными по смещению от этого адреса:
a^[17]:=3.14;


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо