Оптимизация строк
От: #John Европа https://github.com/ichensky
Дата: 12.04.19 06:03
Оценка:
Здравсвуйте,

На ПК-сервере есть 4GB оперативки, .net core приложение.
Есть объект с кучей вложенных списков/объектов ~3GB / (~700к вложенных объектов верхнего уровня).

class Bar {
    public string Name {get; set}
    public string Value {get; set}
    public Other Other {get; set}
}
class Foo{

    public List<Bar> Bars{get; set;}
}


Отдельно от него есть несколько десятков списков(~300mb) разной величины (до 300к строк) по которым происходит поиск данных:
public List<string> CoolNames {get; set;}
// Поиск
var bars=_foo.Bars.Where(x=> CoolNames.Contains(x.Name));



Все эти объекты хранятся в памяти и больше не меняются. Надо соптимизировать поиск данных и колличество исспользуемой памяти.
Есть несколько идей:
1. В классе `Bar`, `Name` сделать `int` типом и добавить соответствующий `CoolName` класс.
class Bar {
    public Name {get; set;}
}
class CoolName{
    public int Id {get;set;}
    public string Name {get; set;}
}
public List<CoolName> CoolNames {get; set;}
// Поиск
var coolName=CoolNames.Single(x=>x.Name="...");
var bars=_foo.Bars.Where(x=> x.Name == coolName.Id);


2. Что бы строки в списке `CoolNames` и `Bar.Name` были одни и те же,
что бы искать нужну строку по ссылке, а не по значению, надо
удалить все строки из объектов `Bar.Name` и заменить их на строки из `CoolNames`
CoolNames.ForEach(coolName=> {

    _foo.Bars.ForEach(bar=>{

        if(coolName==bar.Name){ // сейчас идет сравнение по значению
           bar.Name=coolName;
        }
    });    
});

var bars=_foo.Bars.Where(x=> CoolNames.Any(y=>(object)y == (object)x.Name)); // теперь должен быть поиск по сслыке.


3. Почти такой же вариант как и в во втором случае, только сделать строки Intern.
CoolNames=CoolName.Select(x=> string.Intern(x)).ToList();
_foo.Bars.ForEach(bar=>{
   bar.Name=string.Intern(bar.Name);
});
var bars=_foo.Bars.Where(x=> CoolNames.Any(y=>(object)y == (object)x.Name)); // теперь должен быть поиск по сслыке.


--
Все объекты будут жить до конца жизни приложения, бд ставить на ПК — не вариант.
Какой из приведенных вариантов лучше всего? Какие еще идеи?
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re: Оптимизация строк
От: Sharowarsheg  
Дата: 12.04.19 07:27
Оценка:
Здравствуйте, #John, Вы писали:


J>Отдельно от него есть несколько десятков списков(~300mb) разной величины (до 300к строк) по которым происходит поиск данных:


на каком языке (точнее, какой charset) строки и меняются ли они? и повторяются ли?

сделать список, загнать в него строки и использовать индексы в списке.

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

если достаточно часто попадаются восьмибитные строки, сделать два списка, один для восьмибитных строк, другой для UTF16.

опять же, насколько часто нужны сами строки, по сравнению с тем, насколько часто нужно сравнивать.

И сколько всего строк? скажем, миллион штук максимум если, то номер строки укладывается в 24 бита и еще 7 можно использовать под 128 разных типов сжатия, и при этом индекс будет укладываться в int32. А дальше над сжатием можно надругаться как угодно, включая, например, варианты "если строка один, два, или три восьмибитных символа, то это на самом деле uint24" и тогда старший байт индекса равен нулю, а три младших — это сама строка. А если строка — четыре восьмибитных символа, то старший байт индекса равен 1, а три младших дают индекс в массив uint32. А от четырех до восьми — в массив uint64. И так можно глумиться неограниченно долго.

какие сравнения нужны — больше/меньше или равно/не равно?
Отредактировано 12.04.2019 7:44 Sharowarsheg . Предыдущая версия . Еще …
Отредактировано 12.04.2019 7:41 Sharowarsheg . Предыдущая версия .
Re: Оптимизация строк
От: VladCore  
Дата: 12.04.19 07:42
Оценка: 4 (1)
Здравствуйте, #John, Вы писали:

J>Здравсвуйте,


J>На ПК-сервере есть 4GB оперативки, .net core приложение.


J>Все эти объекты хранятся в памяти и больше не меняются. Надо соптимизировать поиск данных


Используйте BinarySearch вместо Set-ов и Dictionary. Памяти будет В РАЗЫ меньше потреблять, а производительность такая же. String.Intern это второе. Да ещё и один глобюальный на всё.

J> и колличество исспользуемой памяти.


Не храните дважды "одинаковые" строки и объекты

J>Есть несколько идей:

J>1. В классе `Bar`, `Name` сделать `int` типом и добавить соответствующий `CoolName` класс.
J>[cs]
J>class Bar {
J> public Name {get; set;}
J>}
J>class CoolName{
J> public int Id {get;set;}
J> public string Name {get; set;}
J>}

Ну так себе. Может жутко тормозить — вы же все гигабайты в ОДНУ коллекцию засуните.
Отредактировано 12.04.2019 7:45 VladCore . Предыдущая версия . Еще …
Отредактировано 12.04.2019 7:43 VladCore . Предыдущая версия .
Re: Оптимизация строк
От: VladCore  
Дата: 12.04.19 07:55
Оценка:
Здравствуйте, #John, Вы писали:

J>Все объекты будут жить до конца жизни приложения, бд ставить на ПК — не вариант.


MongoDB/Redis это БД по вашему или нет?

Оба варианта — это ровно ОДИН бинарник что в Windows что в Linux, который можно таскать с собой. Их даже отдельно устанавливать не надо. Но если речь идет про сервер и данные не меняются, то вы ещё и получите нулевые затраты на restart приложения или reboot OS.
Re: Оптимизация строк
От: Danchik Украина  
Дата: 12.04.19 08:45
Оценка: 5 (2)
Здравствуйте, #John, Вы писали:

[Skip]

J>--

J>Все объекты будут жить до конца жизни приложения, бд ставить на ПК — не вариант.
J>Какой из приведенных вариантов лучше всего? Какие еще идеи?

Почему бы не попробоать связку SQLite (maybe in memory) + linq2db.
Что-то мне подсказывает, что это может дать неплохой выигрыш, особенно если правильно индексы настроить.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.