Выделить память сразу всем элементам массива класса Line

Автор Тема: Выделить память сразу всем элементам массива класса Line  (Прочитано 884 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
Код - C# [Выбрать]
  1.  
  2. using CAD_DBS = Autodesk.AutoCAD.DatabaseServices;
  3. //...
  4.             CAD_DBS.Line[] lns = new CAD_DBS.Line[2]; // выделяю размер под массив
  5.             // но значения ячеек массива = Null
  6.             // Я конечно могу выделить память для каждого элемента
  7.             for (int i = 0; i < lns.Length; i++)
  8.                 lns[i] = new CAD_DBS.Line();    
  9.             // Разве в C# нет способа выделить память сразу всем элементам без применения цикла?

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
В C# в таком массиве хранятся указатели на Line, а не сами Line.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
В C# в таком массиве хранятся указатели на Line, а не сами Line.
Это  уже понял. Получается, что выделить создать сразу несколько объектов не получится 
Нужно каждому элементу
присваивать
Код - C# [Выбрать]
  1. Lns[i] = new CAD_DB.Line();

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
в таком массиве хранятся указатели
А ну понятно массив - это просто лента указателей в памяти.
А сама память под объекты уже в другом адресном пространстве ОЗУ

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
Можно так:
Код - C# [Выбрать]
  1. CAD_DBS.Line[] lns = new CAD_DBS.Line[] { new CAD_DBS.Line(), new CAD_DBS.Line() };
https://docs.microsoft.com/ru-ru/dotnet/csharp/tour-of-csharp/arrays

Но зачем?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
CAD_DBS.Line[] lns = new CAD_DBS.Line[] { new CAD_DBS.Line(), new CAD_DBS.Line() };
Согласен так конечно тоже можно но только когда там к примеру 5 шт.
А когда и 500 шт. Не буду же я 500 строк писать. Поэтому то и цикл только приходится делать.

Оффлайн Привалов Дмитрий

  • ADN Club
  • ****
  • Сообщений: 350
  • Карма: 67
Это  уже понял. Получается, что выделить создать сразу несколько объектов не получится
Нужно каждому элементу
присваивать

А зачем тебе это понадобилось? Хочешь таким образом что-то ускорить?

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
А зачем тебе это понадобилось? Хочешь таким образом что-то ускорить?
Ну вообще то есть подозрение что это может ускорить работу
Но бороться за какие-то там микросекунды на практике пока что не так уж и важно.
Скорее просто академический интерес к этому.
Потому как в книгах по С++ читал что динамическое выделение памяти - это затратное и дорога операция.
Делал тесты на С++ с выделением большого числа элементов
Мои тесты показали, что быстрее запросить один раз большой кусок памяти,
 чем много раз просить по чуть-чуть.




Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
Мои тесты показали, что быстрее запросить один раз большой кусок памяти,
 чем много раз просить по чуть-чуть.
Нормальные оптимизирующие компиляторы и в C++ и в C# этот вопрос решают за нас.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • ****
  • Сообщений: 350
  • Карма: 67
Ну вообще то есть подозрение что это может ускорить работу
Но бороться за какие-то там микросекунды на практике пока что не так уж и важно.
Скорее просто академический интерес к этому.
.....
Мои тесты показали, что быстрее запросить один раз большой кусок памяти,
 чем много раз просить по чуть-чуть.

Если говорить чисто о массивах и списках, то по моему опыту массив до 300 тысяч элементов по такой схеме работает быстро.
Заметное время выполнения начинается примерно от 500 тысяч элементов и выше, либо когда в цикле запускается другой цикл на создание массива.
Т.е. сама необходимость что-то оптимизировать может начинаться от 1 млн. циклов. (Зависит от железа, помещаемых в массив объектов и других факторов.) В Autocad таких задач мало.

 
Предполагаю, что в C# есть какой то способ выделить память в куче под объекты, вызвать один раз создание объекта  new class() и затем склонировать его в цикле.
Это будет иметь какой-то эффект, но выигрыш может достигать 10% при том, что ты можешь потратить неделю на изучение вопросов и значительно усложнишь код.

Что касается конкретно автокада, то объекты Line и другие являются врапперами над реальными объектами, которые могут храниться в базе данных чертежа, а могут быть не добавлены в нее.
 можно ли их вообще их клонировать, и все ли врапперы можно клонировать в памяти? скорее всего нет.

По скорости массивов я давно тестировал, расклад примерно такой.
Ты использовал массив. и изначально указал его размер что уже быстро. List<> работает примерно в 1,7 раза медленнее.
Далее ты испольовал цикл for, он тоже быстрее цикла foreach раза в 1,5.
Единственное что не оптимально, это вычисление размера массива в цикле for (int i = 0; i < lns.Length; i++)
Для больших массивов и списков нужно делать так:
int count = lns.Length;
for (int i = 0; i < count; i++)

Т.е. получается что работа  Array&for быстрее в 2-3 раза, чем List&foreach.

Кажется вот оно ускорение, но на самом деле нет!

Пустой цикл тебе не нужен, внутри цикла что-то делается.
Когда ты добавишь внутрь цикла Lns = new CAD_DB.Line(); и замеришь разницу Array&for vs List&foreach , то она окажется смехотворно мала 2-5%.
А если внутри цикла работа с Database и Transaction то выйгрышь около нуля.

Поэтому я использую List&foreach практически всегда,  удобнее, кода меньше, с тем же результатом.

Оффлайн Привалов Дмитрий

  • ADN Club
  • ****
  • Сообщений: 350
  • Карма: 67
Скорее просто академический интерес к этому.

Для интереса можешь изучить статью.
Там есть часть того, что тебе может понадобиться.
https://habr.com/ru/post/428676/

Тестируй сперва на своих классах для уменьшения числа сюрпризов, а потом можно с Line поэкспериментировать.

Онлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
Скорее просто академический интерес к этому.

Для интереса можешь изучить статью.
Там есть часть того, что тебе может понадобиться.
https://habr.com/ru/post/428676/

Тестируй сперва на своих классах для уменьшения числа сюрпризов, а потом можно с Line поэкспериментировать.
Думаю, что эта статья не слишком применима для объектов AutoCAD, так как они суть обертки над native ObjectARX.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
int count = lns.Length;
for (int i = 0; i < count; i++)
Да согласен. Получить один раз размер это наверняка должно быть
быстрее чем получать размер при каждой итерации.
Хотя не проверял.
Ведь Length - это просто свойство (ячейка памяти в которой хранится размер)
Полагаю, что доступ к адресу локальной переменной работать должен немного
быстрее чем доступ к адресу свойства Length.

Хотя чтобы реально узнать, что эффективнее нужно смотреть код ассемблера (для двух случаев)
На асме проверка конца цикла - это все равно проверка значения регистра.   

Оффлайн Привалов Дмитрий

  • ADN Club
  • ****
  • Сообщений: 350
  • Карма: 67
Полагаю, что доступ к адресу локальной переменной работать должен немного
быстрее чем доступ к адресу свойства Length.
Ага.

Ведь Length - это просто свойство (ячейка памяти в которой хранится размер)
А вот тут не совсем верное предположение. Выносить размер за цикл, это общая рекомендация для различных коллекций и языков. У разных коллекций могут быть "нюансы" внутри полей или методов, выдающих их размер. Например некоторые коллекции не хранят свой размер, и при каждом запросе проводят итерацию по всем элементам и каждый раз считают их количество. Т.е. при итерации коллекции на млн. можешь получить итерацию   млн.*млн.  и это будет реально медленно. И чтобы не запоминать нюансы, не ловить сюрпризы, и существует эта рекомендация.

Оффлайн Алексей (IdeaSoft)Автор темы

  • ADN
  • *
  • Сообщений: 1124
  • Карма: 5
    • idea-soft.ru
  • Skype: makar_govorun
при каждом запросе проводят итерацию по всем элементам и каждый раз считают их количество
Это конечно жесть так делать.
Каждый раз тупо функция будет считать кол-во.
Но кто знает, может практическое применение есть в этом.

Например, когда я удаляю элементы, то уже не имеет смысла хранить длину массива в локальной переменной.
Так как при каждом удалении кол-во меняется.
Поэтому делаю так:

Код - C# [Выбрать]
  1. for (int i = List.Count-1; i>=0; i--)
  2.   if (Моё условие)
  3.     List.RemoveAt(i);