Директива компилятора для отключения проверки индексатора массива

Я не про то говорю. Вы сначала сказали что игнорировать опыт что обычно границы массивов надо проверять - нельзя. Но про то что в других .Net языках это можно отключать - вы говорите как будто это рандомное решение а не опыт.

Насчёт ниши - почему вы вдруг говорите что только образование. На паскале полно упрощений, программа на нём получается читабельнее и проще, это тоже обсуждали в той теме.

Вообще муть какая-то. Мне кажется, что этим просто не хотят заниматься.

Вы решили ограничить нишу. Понятно…

Это лишь для совместимости со старым кодом. В Java этого нет.

Почему-то мне думается, что хотелки порулить ссылками - это на самом деле неосознанное желание “поруководить” собственным кодом. Когда компьютеры были большими, а их быстродействие и объемы памяти, наоборот, по современным меркам, ничтожными, операционных систем тоже не было, а все писали непосредственно в машинном коде. Хорошие программисты были на вес золота, потому что они умели втиснуть приличного объема программы в эти смешные несколько сотен ячеек оперативной памяти, да еще и добиться от программы приемлемой скорости вычислений. Вас бы в то время - наигрались бы в кодах всласть. Либо не выжили, как программист. Третьего не было дано. Потом появились операционные системы, пакетная обработка данных - и жить стало еще веселее. Счастливых владельцев ЭВМ заставили сдавать в аренду машинное время, если они не могли сами полезно загрузить машину положенное количество времени. Опять хорошие программисты были на коне. Такой программист с лихвой отрабатывал свою высокую зарплату, создавая эффективные по времени выполнения программы и делая при этом минимальное количество ошибок. Ведь за машинное время надо было платить и один час машинного времени обходился примерно столько же, сколько двухнедельная зарплата программиста. Тогда очень важна была оптимизация алгоритмов, а уж знание тайных особенностей компиляторов, заставляющих их генерировать более быстрый код считалось чуть ли не шаманством.

Но это время прошло и вряд ли вернется в том или ином виде.Сейчас промышленно востребованы языки, порождающие в первую очередь надежный самодокументируемый код. А для задач со 100% загрузкой процессора и редкими прерываниями по вводу-выводу существует своя ниша - суперкомпьютеры, многопроцессорные вычислительные комплексы и т.п. С соответствующими специализированными языками. И это точно не Паскаль.

1 лайк

Всё новое - это хорошо забытое старое :slight_smile:

А вот теперь цифры для Админа(и код тоже):

Uses System;
Uses System.Threading;
Uses System.Threading.Tasks;

type
  PInt32 = ^Int32;

procedure SetVal(arr: array [,] of Int32; val: Int32);
begin
  for Var y := 0 to arr.GetLength(0) - 1 do
    for Var x := 0 to arr.GetLength(1) - 1 do
    begin
      arr[x, y] := val;
    end;
end;

function Look(Arr: array [,] of Int32; Val: Int32): Boolean;
begin
  Result := False;
  for Var y := 0 to arr.GetLength(0) - 1 do
    for Var x := 0 to arr.GetLength(1) - 1 do
    begin
      if(arr[x, y] <> Val)
        Then Result := True;
    end;
end;

begin
  var A := new Int32[1000, 1000];
  var B := new Int32[1000, 1000];
  var C := new Int32[1000, 1000];
  SetVal(A, 2);
  SetVal(B, 3);
  var Aptr := Int32(@A[0, 0]);
  var Bptr := Int32(@B[0, 0]);
  var Cptr := Int32(@C[0, 0]);
  GC.Collect();
  var DT := DateTime.Now;
  for Var n := 0 to 99 do
  begin
    for Var y := 0 to 999 do
    begin
      for Var x := 0 to 999 do
      begin
        PInt32(Pointer(Cptr + (y * 1000 + x) * 4))^ := PInt32(Pointer(Aptr + (y * 1000 + x) * 4))^ * PInt32(Pointer(Bptr + (y * 1000 + x) * 4))^;
      end;
    end;
  end;
  Console.WriteLine('PascalABC.NET. Указатели: ' + (DateTime.Now - DT).TotalMilliseconds.ToString());
  Console.WriteLine('Ошибки: ' + Look(C, 6).ToString());
  DT := DateTime.Now;
  for Var n := 0 to 99 do
  begin
    for Var y := 0 to 999 do
    begin
      for Var x := 0 to 999 do
      begin
        C[x, y] := A[x, y] * B[x, y];
      end;
    end;
  end;
  Console.WriteLine('PascalABC.NET. Индексатор: ' + (DateTime.Now - DT).TotalMilliseconds.ToString());
  Console.ReadLine();
end.

Всё ещё сомневаетесь?

P. S. Все результаты получены в Release.

Время то прошло, да вот необходимость осталась. Качество всегда будет востребовано.

Да, это круто.

for Var x := 0 to 999 do
    begin
      for Var y := 0 to 999 do

Порядок тут надо поменять для чистоты. Но всё равно - в 4 раза. Ну - сделайте соответствующие процедуры - и работайте!

Что касается вытягивания двумерного массива в одномерный - то можно сделать и без извращений:

  var aa := new integer[1000*1000];
  var bb := new integer[1000*1000];
  var cc := new integer[1000*1000];
  loop 100 do
    for Var y := 0 to 999 do
    for Var x := 0 to 999 do
    begin
      var r := y * 1000 + x;
      aa[r] := bb[r]+cc[r];
    end;

Этот код работает еще быстрее вашего

И используйте уже нормальный тип integer и паскалевский вывод хотя бы по writeln

Да и замеры времени по MillisecondsDelta

На всякий случай:

2 лайка

Да, не заметил в спешке. Кстати, преобразование pointer->Int32 занимает время? Её ведь можно сократить. Да и вот ещё что, как видите, после получения адреса вызвал сборщика мусора и массив не сместился. В Паскале всё таки фиксируются массивы?

Да вот привык уже к этому :slight_smile: Очень легко в C# переводить, только := на = менять да и всё :smile:

Напишите-ка лучше скрипт, переводящий C# в PascalABC.NET. Сообщество Вам спасибо скажет

2 лайка

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

Глеб, прочитайте внимательно весь мой пост в параллельной ветке (и статью там же по ссылке – см. ниже) про особенности реализации динамической памяти SOH и LOH в CLR.

Что касается конкретно вашего кода:

  • массив из 10^6 эл-тов всегда будет размещен в LOH;
  • одной команды GC.Collect недостаточно, чтобы инициировать дефрагментацию (compaction) LOH;
  • принудительная однократная дефрагментация LOH может быть инициирована только на .NET 4.5.1 и старше;
  • даже правильно инициированная дефрагментация кучи произойдет асинхронно, т.е. в недетерминированный момент времени, а не сразу после GC.Collect;
  • дефрагментация не обязательно приводит к сдвигу в памяти всех объектов кучи!
1 лайк

Надо попробовать.

Тогда вообще проблем не вижу. У меня нет массивов меньше 80 КБ.

Думаю, всё таки, есть смысл разработать механизм фиксации массива. Например для нейросети, фильтры входного слоя занимают примерно 10 КБ, что заставляет их подчиняться сборщику мусора, хотя обращения к элементам происходится десятки, сотни миллионов раз.

1 лайк

Если на него есть неуправляемый указатель, то он фиксируется.

Не понимаю вашу последнюю фразу. Сборщик мусора собирает то, что уже не нужно. Вы хотите это оставить в памяти?

Нет, это был ответ на это:

Если что-то плохо лежит - пусть себе лежит дальше. Мы будем брать то, что лежит хорошо! :sunglasses:

(не помню источник)

А чего ж Вы сразу то не сказали? Вы ведь говорили, что его можно переместить сборщиком мусора и тогда указатель не будет указывать на массив?