В одном проекте была у меня реализация интернированной строки вместо String типа. не только в целях оптимизации памяти, но еще надо было сравнивать/искать эти строки а для интернированыхх строк сравнение(на равенство) сводится к сравнению ссылок, т.к в во внутренний пул интернировааные строки запихиваются используя ordinal сравнение (побайтно) это нам вполне подходило. хороший канал - лайк, подписка ))
Да как раз в одном посте было предложено упростить словари, а я изначально это делал что бы ускорить обмен информацией, а вот оптимизация ОЗУ это был побочный эффект, потом уже целенаправленно занимался оптимизацией. За лайк и подписку спасибо.
@@IQ-120 у меня стаж 22+ года работы. И да я в своё время и на asm писал. Упор был на simd команды ( но это было давно ) + то что показал в этом виде это важно, и ничего сложного в этом нет. Про исследования мне до Рихтера далеко 🤣
@@IQ-120 тут несколько мнений. 1) опытный разработчик работает и он молодец 2) опытный еще делится опытом. В общем предлагаю прекращать чатится. А если есть желание, велком в телегу
👌К активному применению. Единственным минусом данного финта представляется большее потребление процессорного времени на поиск в кэше в приложениях с активным созданием/удалением объектов с такими строками. Тут кому что важнее, как говорится.
Добрый день, а почему бы не сделать 1 ConcurrentDictionary? Идея такая, что при установки значения, мы по ключу ищем значение, если оно там есть, то мы используем его(интернированную строку), если его нет, то мы добавляем её следующим образом map.TryAdd(strValue, strValue); Т.е мы избавляемся от 2х словарей и уменьшаем количество потребляемой оперативной памяти + ускоряем работу этого кэша
Тоже как вариант. Только у меня было такое, я передавал сам дикшенари из строк и интов и сами объекты где строки это числа, и тогда количество передаваемой информации сильно меньше
@@Kulibins1 в случае ConcurrentDictionary int не нужны совсем, как и обращение к словарю и приведение типов, при возврате строки из кэша. Вот пример реализации: public struct StringCache { private string cachedStr; public static implicit operator StringCache(string str) => new() { cachedStr = StringCacheManager.Instance.Cache(ref str) }; public static implicit operator string(StringCache s) => s.cachedStr; public static string[] CacheArray(string[] arr) { for (int i = 0; i < arr.Length; i++) arr[i] = StringCacheManager.Instance.Cache(ref arr[i]); return arr; } public override string ToString() => cachedStr; } internal class StringCacheManager { public static readonly StringCacheManager Instance = new(); private readonly ConcurrentDictionary cacheStorage = new(); public string Cache(ref string str) { if (string.IsNullOrEmpty(str)) return String.Empty; if (cacheStorage.TryAdd(str, str)) return str; return cacheStorage[str]; } }
@@konstantinshapovalov3520 уже писали. Только код я скопировал из проекта где мне нужен был int, т.к. я серелизовал и там передавал int. А так спасибо за активность 👍
@@Kulibins1 Спасибо за идею кстати, сейчас добавил в свой проект. Имхо код класс StringCache StringCacheManager с int и без не плохо было бы на гитхаб тоже выложить. Кстати во втором случае после загрузки данных хранить ConcurrentDictionary не обязательно и можно очистить, а данные все останутся. Освободится доп. память ;)
Спасибо, очень интересно Вместо обжекта который хранит лист или дикшнри было бы лучше сделать через полиморфизм как State паттерн чтобы без кастов было? По идее должно быть чутка быстрее. + имплементацию делать структурой а не объектом чтоб вызовы были быстрее и jit оптимизация получше.
Вроде же рассказал что есть произвольное дерево. Каждый элемент дерева это тэг с устройства, заранее не известны эти тэги и очень зависят от устройств. Но тут есть множество повторений, вот одинаковые строки и оптимизируются. На самом деле много где это может быть. В документных базах данных и т.д.
@@Kulibins1 деревья были, сейчас нет, а если и есть, то они в бд 😁 Если поменять концепцию на cqs + anemic, то там архитектура любых приложений вообще по другому строится, и она проще, производительней легче расширяется и в ней меньше ошибок в следствии её некоторой простоты и дубовости 😁 Было время, были события, деревья, но теперь в одно лицо 200+ микросервисов без ошибок вообще не напрягаясь.
Индексатор принимает строку возвращает число. У меня строке соответствует число. Впринципе можно было сделать фенцию. int GetInt(string value) но с индексатором вызов короче вместо о.GetInt("ля-ля-ля") будет o["ля-ля-ля"]
Спасибо Александр, очень круто и полезно! Хоть я и новичок))
Рад что нравится
В одном проекте была у меня реализация интернированной строки вместо String типа.
не только в целях оптимизации памяти, но еще надо было сравнивать/искать эти строки
а для интернированыхх строк сравнение(на равенство) сводится к сравнению ссылок,
т.к в во внутренний пул интернировааные строки запихиваются используя ordinal сравнение (побайтно)
это нам вполне подходило.
хороший канал - лайк, подписка ))
Да как раз в одном посте было предложено упростить словари, а я изначально это делал что бы ускорить обмен информацией, а вот оптимизация ОЗУ это был побочный эффект, потом уже целенаправленно занимался оптимизацией. За лайк и подписку спасибо.
@@IQ-120 у меня стаж 22+ года работы. И да я в своё время и на asm писал. Упор был на simd команды ( но это было давно ) + то что показал в этом виде это важно, и ничего сложного в этом нет. Про исследования мне до Рихтера далеко 🤣
@@IQ-120 юморист 🤣 Запись и монтаж видео занимает много времени эгоизм должен быть очень большой 😁. У меня это хобби.
@@IQ-120 тут несколько мнений. 1) опытный разработчик работает и он молодец 2) опытный еще делится опытом. В общем предлагаю прекращать чатится. А если есть желание, велком в телегу
Интересная хитрость.
Очень круто! Спасибо
Всегда пожалуйста
Классное видео, а можно подробнее про диагностику в целом сделать видео?
Конечно, сделаю такое видео тоже
👌К активному применению. Единственным минусом данного финта представляется большее потребление процессорного времени на поиск в кэше в приложениях с активным созданием/удалением объектов с такими строками. Тут кому что важнее, как говорится.
Да так и есть
Добрый день, а почему бы не сделать 1 ConcurrentDictionary?
Идея такая, что при установки значения, мы по ключу ищем значение, если оно там есть, то мы используем его(интернированную строку), если его нет, то мы добавляем её следующим образом
map.TryAdd(strValue, strValue);
Т.е мы избавляемся от 2х словарей и уменьшаем количество потребляемой оперативной памяти + ускоряем работу этого кэша
Тоже как вариант. Только у меня было такое, я передавал сам дикшенари из строк и интов и сами объекты где строки это числа, и тогда количество передаваемой информации сильно меньше
@@Kulibins1 в случае ConcurrentDictionary int не нужны совсем, как и обращение к словарю и приведение типов, при возврате строки из кэша. Вот пример реализации:
public struct StringCache
{
private string cachedStr;
public static implicit operator StringCache(string str) =>
new() { cachedStr = StringCacheManager.Instance.Cache(ref str) };
public static implicit operator string(StringCache s) => s.cachedStr;
public static string[] CacheArray(string[] arr)
{
for (int i = 0; i < arr.Length; i++)
arr[i] = StringCacheManager.Instance.Cache(ref arr[i]);
return arr;
}
public override string ToString() => cachedStr;
}
internal class StringCacheManager
{
public static readonly StringCacheManager Instance = new();
private readonly ConcurrentDictionary cacheStorage = new();
public string Cache(ref string str)
{
if (string.IsNullOrEmpty(str))
return String.Empty;
if (cacheStorage.TryAdd(str, str))
return str;
return cacheStorage[str];
}
}
@@konstantinshapovalov3520 уже писали. Только код я скопировал из проекта где мне нужен был int, т.к. я серелизовал и там передавал int. А так спасибо за активность 👍
@@Kulibins1 Спасибо за идею кстати, сейчас добавил в свой проект. Имхо код класс StringCache StringCacheManager с int и без не плохо было бы на гитхаб тоже выложить. Кстати во втором случае после загрузки данных хранить ConcurrentDictionary не обязательно и можно очистить, а данные все останутся. Освободится доп. память ;)
круто!
Спасибо
Спасибо, очень интересно
Вместо обжекта который хранит лист или дикшнри было бы лучше сделать через полиморфизм как State паттерн чтобы без кастов было? По идее должно быть чутка быстрее. + имплементацию делать структурой а не объектом чтоб вызовы были быстрее и jit оптимизация получше.
Да, можно с оптимизировать еще.
Вдруг кому пригодится реализация на HashSet:
public struct StringCache
{
private string cachedStr;
public static implicit operator string(StringCache s) => s.cachedStr;
public static explicit operator StringCache(string str) =>
new() { cachedStr = StringCacheManager.Instance.Cache(ref str) };
public static string[] CacheArray(string[] arr)
{
for (int i = 0; i < arr.Length; i++)
arr[i] = StringCacheManager.Instance.Cache(ref arr[i]);
return arr;
}
public static void ClearCache() => StringCacheManager.Instance.ClearCache();
public override string ToString() => cachedStr;
}
internal class StringCacheManager : IDisposable
{
public static readonly StringCacheManager Instance = new();
private readonly HashSet cacheStorage = new();
private readonly ReaderWriterLockSlim cacheLock = new();
public bool IsDisposed { get; private set; }
private StringCacheManager()
{
Debug.Assert(Instance == null, "Should be one instance of StringCacheManager");
}
public string Cache(ref string str)
{
if (IsDisposed)
throw new ObjectDisposedException(nameof(StringCacheManager));
if (string.IsNullOrEmpty(str))
return String.Empty;
cacheLock.EnterReadLock();
try
{
if (cacheStorage.TryGetValue(str, out var cacheStr))
return cacheStr;
}
finally
{
cacheLock.ExitReadLock();
}
cacheLock.EnterWriteLock();
try
{
if(cacheStorage.Add(str))
return str;
if (cacheStorage.TryGetValue(str, out var cacheStr))
return cacheStr;
}
finally
{
cacheLock.ExitWriteLock();
}
return str;
}
public void ClearCache()
{
if (IsDisposed)
throw new ObjectDisposedException(nameof(StringCacheManager));
cacheLock.EnterWriteLock();
try
{
cacheStorage.Clear();
}
finally
{
cacheLock.ExitWriteLock();
}
}
public void Dispose()
{
cacheLock?.Dispose();
IsDisposed = true;
}
}
Хорошая реализация 👍
Не совсем понимаю, где это вы в базе столько одинаковых строк нарыли
Вроде же рассказал что есть произвольное дерево. Каждый элемент дерева это тэг с устройства, заранее не известны эти тэги и очень зависят от устройств. Но тут есть множество повторений, вот одинаковые строки и оптимизируются. На самом деле много где это может быть. В документных базах данных и т.д.
+
Ушел от рич модели классов на анемик. Подобных проблем нет, так как нет самой необходимости в событиях 😂
Ооп это зло.
события это как пример. думаю дерево чего-нибудь у многих есть, так же как событие, например клик.
@@Kulibins1 деревья были, сейчас нет, а если и есть, то они в бд 😁
Если поменять концепцию на cqs + anemic, то там архитектура любых приложений вообще по другому строится, и она проще, производительней легче расширяется и в ней меньше ошибок в следствии её некоторой простоты и дубовости 😁
Было время, были события, деревья, но теперь в одно лицо 200+ микросервисов без ошибок вообще не напрягаясь.
@@АнтонБ-х9у модель данных это не то о чём это видео. то что у вас дерево в базе данных => вы вообще не поняли суть темы
@@Kulibins1 я понял, надесь и вы поняли, что если сделать архитектуру кода другой, то ваша тема просто никогда не возникнет в вашем проекте 😁
Будьте добры, кто-нибудь, объясните строку
**public int this[string value]**
Индексатор принимает строку возвращает число. У меня строке соответствует число. Впринципе можно было сделать фенцию. int GetInt(string value) но с индексатором вызов короче вместо о.GetInt("ля-ля-ля") будет o["ля-ля-ля"]
@@Kulibins1 спасибо большое, почитал про индексаторы, был пробел в знаниях.
Очень напрягает затыки звука. Резко пропадает звук. Заставляет напрагяться
В новых видео такого нет. Шумодав...