Как нельзя создавать переменные, списки, массивы и как можно

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
Сегодня углубился чуток в С#.
И знаете что узнал?
C#:
string line_1 = ""; // так не правильно
string line_2 = string.Empty; //  так в самый раз

List<string> list_1 = new List<string>(); // так не нужно делать
List<string> list_2 = Enumerable.Empty<string>().ToList(); // а вот так что доктор прописал

string[] arr_1 = new string[0]; // так не нужно делать
string[] arr_2 = Enumerable.Empty<string>().ToArray(); // а вот так что доктор прописал
Кто знает в чём разница?
Может кто-то объяснить подробнее?

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

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 691
Баллы
113
Я переменные создаю что бы в них что то записать. Какая разница что в них будет на начальном этапе ?
а string.Empty наверняка выдаст ошибку при попытке обращения к ней, если не будет записи туда данных например через try. а потом надо еще усложнить код дополнительной проверкой переменной на Empty ?
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
Я переменные создаю что бы в них что то записать. Какая разница что в них будет на начальном этапе ?
а string.Empty наверняка выдаст ошибку при попытке обращения к ней, если не будет записи туда данных например через try. а потом надо еще усложнить код дополнительной проверкой переменной на Empty ?
Нет, почему? string.Empty не выдаст ошибку - это ведь пустая строка, разницы между "" и string.Empty нет, просто в первом случае у нас есть 100500 переменных которые ссылаются на одно место в памяти, а во втором случае - будет создано 100500 мест в памяти (для каждой своё). И предположим, что код у нас построен так, что не ко всем переменным мы обращаемся в процессе работы (не всем и не всегда присваиваем какие-то значения) - в этом случае нет нужды держать в памяти зарезервированное место. Но, я ещё глубоко не разобрался - из-за чего создал тему, может кто что-то подскажет, а может кто-то уже данную фишку использует.
 
  • Спасибо
Реакции: Alexmd

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
string line_2 = string.Empty; // так в самый раз
Используется уже существующая константа (пустой строки), а не создаётся новая (при релизной сборке, такое навряд ли должно быть).
List<string> list_1 = new List<string>(); // так не нужно делать
Это норм, так и делают.
List<string> list_2 = Enumerable.Empty<string>().ToList(); // а вот так что доктор прописал
Это какой-то изврат с конвертацией пустого Enumerable в список - не надо так.
string[] arr_1 = new string[0]; // так не нужно делать string[] arr_2 = Enumerable.Empty<string>().ToArray(); // а вот так что доктор прописал
Тоже самое, только с массивом.
 
  • Спасибо
Реакции: DevOps, Astraport и BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
Это какой-то изврат с конвертацией пустого Enumerable в список - не надо так.
Вы утверждаете что это не правильно или это предположение именно из-за сложности/красивости написания конструкции?
Я ещё не придумал как наглядно продемонстрировать разницу, но думаю разница должна быть очевидной, если запульнуть какой-то ParallelFor в котором на каждой итерации создавать коллекции, добавлять туда например по 1000 строк и по результатам сравнить время на выполнение и сравнить размер затраченой ОЗУ (как к ней получить доступ ещё не нашел).
 

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
Я бы ещё придрался к написанию, в C# принят CamelCase.

+ если виден создаваемый тип, можно написать для краткости:
var list1 = new List<string>();
 
  • Спасибо
Реакции: BAZAg

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
Вы утверждаете что это не правильно или это предположение именно из-за сложности/красивости написания конструкции?
И неправильно и некрасиво.
Если нужен Enumerable - используйте его, но обычно его возвращают функции уже с содержимым и (вроде) в него потом нельзя добавить.
Я ещё не придумал как наглядно продемонстрировать разницу, но думаю разница должна быть очевидной, если запульнуть какой-то ParallelFor в котором на каждой итерации создавать коллекции, добавлять туда например по 1000 строк и по результатам сравнить время на выполнение и сравнить размер затраченой ОЗУ (как к ней получить доступ ещё не нашел).
Используйте массив.
 
  • Спасибо
Реакции: BAZAg

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
Суть в том, что массиву требуется задать размер, что бы он сразу выделил память.
string[] arr_1 = new string[1000];
и лучше его переиспользовать по возможности. Можно много разных способов для оптимизации найти, но лучше начать с профильных тем (и не от новичком).
 
  • Спасибо
Реакции: Alexmd и BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
И неправильно и некрасиво.
Первое что попалось под руку по данному поводу link - автор утверждает что нужно по другому.
Мне его доводы кажутся объективными.
Хотя может я действительно не всё понял (из-за чего и создал тему уточняющую данный вопрос).
 

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
List в себе содержит массив малого размера и при добавлении элементов его надо увеличивать, а это требует выделение памяти и копирование существующего массива.
И так кучу раз за короткий промежуток времени - поэтому и нагрузка заметная.

List'у при создании можно задать размер.
var list = new List<string>(1000);
 
  • Спасибо
Реакции: BAZAg

volody00

Client
Регистрация
06.09.2016
Сообщения
794
Благодарностей
814
Баллы
93
А ещё если вы планируете видоизменять переменную, то вам вообще не стоит пользоваться string, а вместо него использовать StringBuilder.

Может я ещё не дорос, но как по мне ударяться в такие мелочи перебор. Учитывая какие сейчас компьютеры, едва ли удастся заметить разницу, тем более создавая шаблоны для ZennoPoster (хотя вообще я в этом ничего не понимаю и вполне могу ошибаться)
 
  • Спасибо
Реакции: Yuriy Zymlex и BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
List'у при создании можно задать размер.
Даже если задать какой-то размер - то это ведь не то же что задать ссылку на уже существующий (кешированный) объект.
Получается, что утверждение в стартовом посте верно.
Или всё же есть ошибка и нужно продолжать использовать new List<string>()?
 

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
  • Спасибо
Реакции: BAZAg и volody00

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
А ещё если вы планируете видоизменять переменную, то вам вообще не стоит пользоваться string, а вместо него использовать StringBuilder.

Может я ещё не дорос, но как по мне ударяться в такие мелочи перебор. Учитывая какие сейчас компьютеры, едва ли удастся заметить разницу, тем более создавая шаблоны для ZennoPoster (хотя вообще я в этом ничего не понимаю и вполне могу ошибаться)
Разница заметна, когда генерация 1000 сайтов у заказчика занимала неделю - а стала занимать сутки и всё что было заменено - перешел вместо списков на Enumerable и создавал их способом указанном в шапке (было это годик назад, но тогда я ещё не особо понимал почему так работает быстрее - а сейчас уже более-менее понимание пришло).
 
  • Спасибо
Реакции: volody00

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
Думаю вся проблема из-за создания нового списка в цикле, а не использования уже существующего.
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 765
Благодарностей
2 407
Баллы
113
Думаю вся проблема из-за создания нового списка в цикле, а не использования уже существующего.
Принцип действия там был примерно такой - было 100 баз данных по 1гб в каждой.
Нужно было получить случайных 5000 000 строчек (по какому-то количеству с каждой).
Разделить их случайно на 1000 списков.
Каждую строчку разбить по разделителю.
То что получилось - одеть в случайные сгенерированные теги.
Дальше всё собрать обратно в одну строку.
И с каждого списка сформировать новую базу данных.

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

Yuriy Zymlex

Moderator
Команда форума
Регистрация
24.10.2016
Сообщения
6 373
Благодарностей
3 297
Баллы
113
Часть логики можно перенести на каждую базу данных.
Как выше посоветовали - попробовать StringBuilder.
Если память позволяет, строки можно попробовать хранить иначе (м.б. как байты), заранее выделив под них память в массивах.
 
  • Спасибо
Реакции: BAZAg

RoyalBank

Client
Регистрация
07.09.2015
Сообщения
557
Благодарностей
547
Баллы
93
string line_1 = ""; // так не правильно
string line_2 = string.Empty; // так в самый раз
Я объявляю через null, затем присваиваю значение. Если не присвоить и обратиться, то будет ошибка, но для этого есть проверка на isNullOrWhiteSpace.
 
  • Спасибо
Реакции: bigloafer и BAZAg

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)