Последствия реинициализация массива с изменением длинны.

Программирование на Юнити.

Последствия реинициализация массива с изменением длинны.

Сообщение AlexandrBuryakov 26 янв 2019, 15:16

List не самый производительный массив. (Причину необходимости оптимизировать не обсуждаем.)
По этому принял решение хранить некоторые данные в List, но инициализировать с помощью него обычный массив с фиксированной длинной для повышения производительности.
В определённый момент, иногда реже иногда чаще, в List изменяются, добавляются или удаляются какие то данные. После этого нужно обновить обычный массив.
Я произвожу повторную инициализацию фиксированного массива с новой длинной так:

Синтаксис:
Используется csharp

        //Объявления
        List<Rigidbody> rbList = new List<Rigidbody> ();
        Rigidbody [ ] rbArray;
        int rbMax;

        //Метод инициализации и повторной инициализации
        public void RbArrayReBuf (){

                rbMax = rbList.Count;                           //Максимум rb
                rbArray = new Rigidbody [ rbMax ];              //Создаём массив
                rbList.CopyTo ( rbArray );                      //Копируем в массив

        }

 


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

Основной смыл вопроса в том, не будет ли утечки или ещё какой проблемы от этого способа?

Спасибо.
AlexandrBuryakov
UNIт
 
Сообщения: 59
Зарегистрирован: 26 янв 2019, 14:36

Re: Последствия реинициализация массива с изменением длинны.

Сообщение ~AvA~ 26 янв 2019, 20:06

Даже страшно начинать отвечать.. )

Давай всё же не будем обходить стороной и обсудим, какие проблемы с производительностью у листа?
А также подумаем заодно, почему его можно создавать с заданной Capacity, что это решает?
Ответ на этот вопрос в принципе порешает твои проблемы и серьёзно упростит код! )

А то ты спрашиваешь об утечках, при копирровании из листа в массив.. прям .. ну я не знаю, кто-то менее нервный чем я может ответить? :))

P.S: Ты же в курсе, что то, что ты делаешь - это изобретаешь лист?
Аватара пользователя
~AvA~
UNIверсал
 
Сообщения: 351
Зарегистрирован: 17 фев 2015, 13:09

Re: Последствия реинициализация массива с изменением длинны.

Сообщение seaman 26 янв 2019, 23:39

Ты же в курсе, что то, что ты делаешь - это изобретаешь лист?

+ 100500
seaman
Адепт
 
Сообщения: 7867
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: Последствия реинициализация массива с изменением длинны.

Сообщение Cr0c 27 янв 2019, 14:28

Лист инпаксулирует внутри массив. Главное отличие листа от массива - это проверка индекса при запросе данных и геттер/сеттер при работе с данными.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 2970
Зарегистрирован: 19 июн 2015, 13:50
Skype: i_cr0c

Re: Последствия реинициализация массива с изменением длинны.

Сообщение AlexandrBuryakov 27 янв 2019, 19:20

Спасибо за ответ.)
В каждом FixedUpdate мне нужно производить сравнение и вычисление некоторых параметров элементов между собой.
То есть, если элементов 100, то это ~10000 сравнений и вычислений (не будем учитывать оптимизацию избегающую повторений сравнения).
В таком случае простой массив в цикле будет эффективнее чем лист, разве нет? (Где то читал про то, что лист всё таки менее "лёгкий" чем массив)
Я не супер программист, но видел статью которая приводит пример именно в Unity повышения производительности при убирании всех свойств (как раз геттера и сеттера которые, как я только что узнал, есть в List).
Да и статьи про 10000 вызовов тоже видел, где только сами вызовы сжирают кучу ресурсов, если их неймоверно много.
Переинициализироваться List будет редко, потому ~10000 запросов через геттер излишен.

В общем мне тут нужна максимальная производительность, но лезть в дебри ниже C# врятли смогу. И так боюсь всего этого из-за того, что привык к контролю железа, а тут не с могу понять, что под капотом, всё же PC и микроконтроллеры, как песчинка и луна по количеству процессов.
Если переинициализация никак пагубно не влияет, то тогда спасибо за ответ. Интересная информация.)

P.S. Видимо создание собственного примерного List, последствия возни с микроконтроллерами где всё контролируется и всегда изобретается новый велосипед, ибо ресурсов мало.)
AlexandrBuryakov
UNIт
 
Сообщения: 59
Зарегистрирован: 26 янв 2019, 14:36

Re: Последствия реинициализация массива с изменением длинны.

Сообщение Cr0c 27 янв 2019, 23:28

~AvA~ писал(а): его можно создавать с заданной Capacity

Вот же ответ - в готовый массив пихать. А по поводу
AlexandrBuryakov писал(а):Да и статьи про 10000 вызовов тоже видел, где только сами вызовы сжирают кучу ресурсов
это было про Update в скриптах, а не вызовы простых гет/сет. С ними критично будет при 1кк вызовах и более без распараллеливания процесса.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 2970
Зарегистрирован: 19 июн 2015, 13:50
Skype: i_cr0c

Re: Последствия реинициализация массива с изменением длинны.

Сообщение lafin 13 фев 2019, 17:20

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


1. Поле Rigidbody [ ] rbArray это не сам массив, а переменная, хранящая ссылку на массив. "Инициализации массива новой длиной" у тебя нет. Это вообще невозможно. Длина массивов фиксированная, задаётся при создании и никогда не меняется.

Ты просто создаешь новый массив, копируешь в него элементы из списка и записываешь ссылку на этот новый массив в переменную rbArray, затирая ссылку на старый массив. Если на старый массив ссылок нигде больше не хранится, его когда-нибудь "уничтожит" сборщик мусора.

2. Весь метод RbArrayReBuf можно заменить одной строкой: rbArray = rbList.ToArray();

AlexandrBuryakov писал(а):В таком случае простой массив в цикле будет эффективнее чем лист, разве нет? (Где то читал про то, что лист всё таки менее "лёгкий" чем массив)


Запомни простой принцип - никогда не оптимизировать наугад. Даже так: НИКОГДА НЕ ОПТИМИЗИРОВАТЬ НАУГАД. Иначе могут быть сюрпризы.

Если кто-то где-то в интернете написал, что А быстрее Б, это
- не значит, что так на самом деле;
- не значит, что А быстрее Б сейчас (возможно было 5 лет назад);
- не значит, что А быстрее Б везде (в Net Framework, в Net Core, в Mono может быть по-разному):
- не значит, то А быстрее Б в любых задачах или вариантах использования;
- не значит, что А настолько быстрее Б, что имеет смысл менять Б на А везде;
- ...
- может быть, так оно и есть, но кто ж гарантирует?

1. Если веришь, что оптимизированный вариант будет быстрее, надо взять и сравнить. Тогда ты будешь не верить, а точно знать, быстрее ли он и насколько быстрее. Бывает, что медленнее. Бывает, что да, действительно быстрее, но настолько незначительно, что такое ускорение не стоит усложнения кода, которое для него требуется.

2. Если ты думаешь, что знаешь, что оптимизированный вариант будет быстрее, надо взять и сравнить. Тогда ты будешь не думать, что знаешь, а действительно знать.

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

Бывает, что скорость не то чтобы прям важна, но хочется попробовать ещё оптимизировать. Просто настроение такое. Почему бы и нет, если хочется. Всё равно надо сравнивать варианты, чтобы не сделать хуже.
lafin
UNец
 
Сообщения: 6
Зарегистрирован: 30 июл 2018, 15:38

Re: Последствия реинициализация массива с изменением длинны.

Сообщение AlexandrBuryakov 22 фев 2019, 19:55

Спасибо за объяснения!
AlexandrBuryakov
UNIт
 
Сообщения: 59
Зарегистрирован: 26 янв 2019, 14:36

Re: Последствия реинициализация массива с изменением длинны.

Сообщение Woolf 23 фев 2019, 03:09

Cr0c писал(а):Лист инпаксулирует внутри массив. Главное отличие листа от массива - это проверка индекса при запросе данных и геттер/сеттер при работе с данными.


Нууу.. Теоретически это не так. Правильно сделанный List это не массив, это динамическая структура, к массивам не имеющая отношения. Но технически в сишарп лист реализован именно через массивы, что дурость, конечно, несусветная, ибо на корню убивает все преимущества List, а именно, очень быстрое изменение своих размеров, причем, как увеличение, так и уменьшение, без каких либо сдвигов элементов. Но так есть и с этим приходится жить, понимая, что нативный сишарповский лист лучше не уменьшать, иначе будете иметь проблемы с производительностью. Быстрее новый создать на основе старого.
Разработчик Atom Fishing - Рыбалка на поплавок, донку, нахлыст, блесну в постъядерный период.
Разработчик Atom Fishing II - Первая 3D MMO про рыбалку
Аватара пользователя
Woolf
Адепт
 
Сообщения: 6845
Зарегистрирован: 02 мар 2009, 16:59

Re: Последствия реинициализация массива с изменением длинны.

Сообщение Cr0c 23 фев 2019, 11:56

Woolf писал(а):очень быстрое изменение своих размеров, причем, как увеличение, так и уменьшение, без каких либо сдвигов элементов

LinkedList?
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 2970
Зарегистрирован: 19 июн 2015, 13:50
Skype: i_cr0c

Re: Последствия реинициализация массива с изменением длинны.

Сообщение lafin 07 май 2019, 16:11

Woolf писал(а):Правильно сделанный List это не массив, это динамическая структура, к массивам не имеющая отношения. Но технически в сишарп лист реализован именно через массивы, что дурость, конечно, несусветная, ибо на корню убивает все преимущества List, а именно, очень быстрое изменение своих размеров, причем, как увеличение, так и уменьшение, без каких либо сдвигов элементов. Но так есть и с этим приходится жить, понимая, что нативный сишарповский лист лучше не уменьшать, иначе будете иметь проблемы с производительностью. Быстрее новый создать на основе старого.


Вообще, list/список, если без специальных оговорок, ― это просто упорядоченная коллекция элементов, обычно нефиксированой длины. Остальное ― детали реализации.

У одно/двусвязных реализаций списка есть три большие проблемы, которые сужают их область применения до близкой к нулю в процентном отношении:

1. Перерасход памяти. Размер элемента связного равен размеру единицы данных, плюс размер указателя на следующий элемент (или размер двух указателей: на следующий и предыдущий элементы). Тут и сам перерасход памяти, и факт того что в кэш процессора помещается меньше полезных данных, т.к. они разбавлены ненужными служебными. Размер элемента списка на основе массивов равен просто размеру единицы данных.

2. Общие тормоза от того, что элементы списка в общем случае разбросаны по памяти как попало. Ты прочитал один элемент, хочешь прочитать следующий за ним, а он лежит в памяти далеко и отсутствует в кэше процессора. В списке на основе массивов, если ты прочитал один элемент, то соседние почти наверняка тоже сразу окажутся в L1-кэше и доступ к ним будет на два порядка быстрее, чем если читать из памяти.

3. Невозможность доступа к элементу по индексу. В списке из N элементов, чтобы до среднего добраться, надо N/2 других перечитать. И дело не только в том, что их N/2, но ещё смотри пункт 2, в худшем случае умноженный в N/2 раз. В списке же на основе массивов доступ по индексу ― элементарное действие.

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

PS:
4. В списке на основе массивов умный компилятор может догадаться и векторизовать какую-нибудь несложную операцию над элементами, что может ускорить обработку в несколько раз. Не факт, что догадается, но теоретически может. Со связными списками такое проделать затруднительно.
lafin
UNец
 
Сообщения: 6
Зарегистрирован: 30 июл 2018, 15:38

Re: Последствия реинициализация массива с изменением длинны.

Сообщение ~AvA~ 07 май 2019, 17:43

То, о чём ты пишешь (связанный список), реализован в с# как класс LinkedList и вообще совсем другое, отличное от того, что здесь советовали использовать..
Говорили мы за стандартный List , который есть массив с изменяющейся длиной (реализовано путём копирования старого массива в новый, с увеличенной длиной) и отлично подходящие для того, что пытается переизобрести ТС
Аватара пользователя
~AvA~
UNIверсал
 
Сообщения: 351
Зарегистрирован: 17 фев 2015, 13:09

Re: Последствия реинициализация массива с изменением длинны.

Сообщение ~AvA~ 07 май 2019, 17:46

А, сорян, ты отвечал Woolf , проморгал ))
А и про линкедлист уже писали, совсем старый стал.. из дискуссии выпал)
Аватара пользователя
~AvA~
UNIверсал
 
Сообщения: 351
Зарегистрирован: 17 фев 2015, 13:09

Re: Последствия реинициализация массива с изменением длинны.

Сообщение gnom6584 07 май 2019, 21:23

Не читал полностью тему, и то что тут отвечали, но реиницилизация массива = минус память, уже создавал тему с бомбежкой на этот счет, в итоге мне никто не ответил как это исправить, да и в интернете я чет не особо нашел, как это сделать, даже вызов GC.Collect() не помогает, хотя мой массив был статический, может по-другому все иначе, но вы проверьте все равно
gnom6584
UNец
 
Сообщения: 45
Зарегистрирован: 03 май 2019, 00:17

Re: Последствия реинициализация массива с изменением длинны.

Сообщение ~AvA~ 07 май 2019, 22:08

gnom6584 писал(а):реиницилизация массива = минус память... но вы проверьте все равно

Пошёл проверил!
Невероятно, но факт - реинициализация создаёт новый объект в памяти, а старый, на которой больше никто не ссылается, тусит в памяти до момента пока его не подгребёт коллектор.. Ну, так работает CLR в .net, а что были сомнения или чего?
Аватара пользователя
~AvA~
UNIверсал
 
Сообщения: 351
Зарегистрирован: 17 фев 2015, 13:09

След.

Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4