Структурный доступ к MemoryMappedFile
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.05.21 02:49
Оценка:
Всем привет.
Разбираюсь с эффективным произвольным доступом к файлу из-под .Net.

Идея сводится к тому, чтобы отобразить файл в память, а затем работать с ним как со Span<T>, где T — некоторый struct тип.
Смысл идеи — в том, чтобы избежать какой-либо "упаковки/распаковки" или копирований данных.
Бегло погуглил, нашёл несколько проблем без опубликованных решений, и понял, что там не вполне понимаю, как это всё сделать корректно. Как гарантировать, что время жизни Span<T> не превысит время жизни View?
Как работать с файлами длиннее 2GB?
По идее, должен быть какой-то способ работать с View как с Memory<T>, но я пока что не вьехал, как именно это сделать.
Продолжаю читать всякие
https://github.com/dotnet/runtime/issues/37227
https://github.com/dotnet/runtime/issues/24805
и прочее. Если кто-то уже разобрался — ткните носом, куда читать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Структурный доступ к MemoryMappedFile
От: VladCore  
Дата: 07.05.21 04:55
Оценка: 117 (1)
Здравствуйте, Sinclair, Вы писали:

S>Всем привет.

S>Разбираюсь с эффективным произвольным доступом к файлу из-под .Net.

S>Идея сводится к тому, чтобы отобразить файл в память, а затем работать с ним как со Span<T>, где T — некоторый struct тип.

S>Смысл идеи — в том, чтобы избежать какой-либо "упаковки/распаковки" или копирований данных.
S>Бегло погуглил, нашёл несколько проблем без опубликованных решений, и понял, что там не вполне понимаю, как это всё сделать корректно. Как гарантировать, что время жизни Span<T> не превысит время жизни View?
S>По идее, должен быть какой-то способ работать с View как с Memory<T>, но я пока что не вьехал, как именно это сделать.
S>Продолжаю читать всякие
S>https://github.com/dotnet/runtime/issues/37227
S>https://github.com/dotnet/runtime/issues/24805
S>и прочее. Если кто-то уже разобрался — ткните носом, куда читать.

непонятно что именно непонятно. 🙃

вот Span<int> на 2 гигабайта плюс 42 числа. без копирования упаковки распаковки.
using System;
using System.IO;
using System.IO.MemoryMappedFiles;

class Program
{
    static unsafe void Main(string[] args)
    {
        int length = (int) (2L * 1024 * 1024 * 1024 / 4 + 42);
        using (FileStream fs = new FileStream(@"v:\large.data", FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
        {
            fs.Position = length * 4L - 1;
            fs.WriteByte(0);
        }

        Console.WriteLine($"length: {length:n0}");
        using (var mmf = MemoryMappedFile.CreateFromFile(@"v:\large.data", FileMode.Open, "img-1"))
        {
            using (var accessor = mmf.CreateViewAccessor(0, length * 4L))
            {
                byte* pointer = null;
                accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);

                Span<int> arr = new Span<int>(pointer, length);
                arr[1] = 0x07070707;
                arr[length - 1] = 0x06060606;
            }
        }
    }
}


S>Как гарантировать, что время жизни Span<T> не превысит время жизни View?


необходимо, хоть и не достаточно, что бы время жизни View и Span контролировал один и тот же владелец.
Гарантировано если надо, то как в примере выше — оба экземпляра локальные.

Вот тут посложнее гайд есть про ownership, consumption и lease: https://docs.microsoft.com/en-us/dotnet/standard/memory-and-spans/memory-t-usage-guidelines

Или ты хотел что было как с Managed Heap все было просто? 😉
Отредактировано 07.05.2021 7:55 VladCore . Предыдущая версия . Еще …
Отредактировано 07.05.2021 5:02 VladCore . Предыдущая версия .
Re[2]: Структурный доступ к MemoryMappedFile
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.05.21 08:07
Оценка:
Здравствуйте, VladCore, Вы писали:
Ага, то есть Span может покрыть sizeof(T)*int.MaxValue. Уже неплохо.
Теперь бы ещё разобраться, как сделать так, чтобы это работало в нормальном таком многопоточном веб-сервисе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Структурный доступ к MemoryMappedFile
От: VladCore  
Дата: 07.05.21 08:22
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Теперь бы ещё разобраться, как сделать так, чтобы это работало в нормальном таком многопоточном веб-сервисе.


так это совсем всё просто. достаточно задавать имя MMF одинаковое в "конструкторе". в моем примере это "img-1"

Именованые MMF даже между процессами работают корректно, не только между потоками. Т.е. если один процесс загрузил старницу N и второй процесс хочет прочитать/записать ту же страницу, то память в обоих процессах физически используется одна и та же. и разумеется страница второй раз для второго процесса с диска в память НЕ грузится 🏆 указатели в адресных пространствах будут разные, а память под ними будет одна. В метриках производительности даже два раздельных счетчика есть: Major Page Faults и Minor Page Faults
Отредактировано 07.05.2021 8:32 VladCore . Предыдущая версия . Еще …
Отредактировано 07.05.2021 8:30 VladCore . Предыдущая версия .
Отредактировано 07.05.2021 8:26 VladCore . Предыдущая версия .
Re[4]: Структурный доступ к MemoryMappedFile
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.05.21 10:09
Оценка:
Здравствуйте, VladCore, Вы писали:
VC>Именованые MMF даже между процессами работают корректно, не только между потоками. Т.е. если один процесс загрузил старницу N и второй процесс хочет прочитать/записать ту же страницу, то память в обоих процессах физически используется одна и та же. и разумеется страница второй раз для второго процесса с диска в память НЕ грузится 🏆 указатели в адресных пространствах будут разные, а память под ними будет одна. В метриках производительности даже два раздельных счетчика есть: Major Page Faults и Minor Page Faults
Есть подозрения, что это на корню убьёт производительность.
Ну, то есть смотри: вот у нас клиент отправляет нам какой-то запрос, типа select * from people where age > 18 and gender = 'F'.
Наш сервис запрос получает, как-то там его разбирает, и начинает выполнять.
Для этого ему потребуется прыгать по страничкам базы данных взад-вперёд, выполняя Index Seek с последующим Bookmark Lookup.
Мне решительно не хочется тратить миллисекунды на MemoryMappedFile.CreateFromFile, который будет явно очень дорогим. (нутром (с) чую)
Более того — т.к. это всё один процесс с одним address space, то не очень хочется даже и плодить ViewAccessor-ов к нему, т.к они будут забивать address space.
Даже невзирая на то, что физически это всё будут одни и те же странички.

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

Вот с учётом этого всего похоже, что имеет смысл удерживать между запросами собственно и файл и аксессор; а Span<DbPage> получать из них unsafe магией по мере необходимости.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Структурный доступ к MemoryMappedFile
От: VladCore  
Дата: 07.05.21 11:37
Оценка: 78 (1)
Здравствуйте, Sinclair, Вы писали:

VC>>Именованые MMF даже между процессами работают корректно, не только между потоками. Т.е. если один процесс загрузил старницу N и второй процесс хочет прочитать/записать ту же страницу, то память в обоих процессах физически используется одна и та же. и разумеется страница второй раз для второго процесса с диска в память НЕ грузится 🏆 указатели в адресных пространствах будут разные, а память под ними будет одна. В метриках производительности даже два раздельных счетчика есть: Major Page Faults и Minor Page Faults

S>Есть подозрения, что это на корню убьёт производительность.
S>Ну, то есть смотри: вот у нас клиент отправляет нам какой-то запрос, типа select * from people where age > 18 and gender = 'F'.
S>Наш сервис запрос получает, как-то там его разбирает, и начинает выполнять.
S>Для этого ему потребуется прыгать по страничкам базы данных взад-вперёд, выполняя Index Seek с последующим Bookmark Lookup.
S>Мне решительно не хочется тратить миллисекунды на MemoryMappedFile.CreateFromFile, который будет явно очень дорогим. (нутром (с) чую)
S>Более того — т.к. это всё один процесс с одним address space, то не очень хочется даже и плодить ViewAccessor-ов к нему, т.к они будут забивать address space.
S>Даже невзирая на то, что физически это всё будут одни и те же странички.

S>Хочется сразу начать скакать по данным, как дебил на дискотеке, не тратя времени на отображение уже отображённого.


S>Вот с учётом этого всего похоже, что имеет смысл удерживать между запросами собственно и файл и аксессор; а Span<DbPage> получать из них unsafe магией по мере необходимости.


тогда один accessor создать на всё время жизни сервиса и хватит. или нужна поддержка 32х битной ОС?
Re[6]: Структурный доступ к MemoryMappedFile
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.05.21 12:24
Оценка:
Здравствуйте, VladCore, Вы писали:

VC>тогда один accessor создать на всё время жизни сервиса и хватит. или нужна поддержка 32х битной ОС?

Думаю, смысла нет. Сразу x64 и никаких гвоздей.
Спасибо, вы мне очень помогли.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 07.05.2021 12:44 Sinclair . Предыдущая версия .
Re: Структурный доступ к MemoryMappedFile
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.05.21 01:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Смысл идеи — в том, чтобы избежать какой-либо "упаковки/распаковки" или копирований данных.


Это не задача, а решение. Не факт, что оптимальное. Какова задача то? Зачем в веб-сервисах доступ к содержимому файла с проекцией в помять?

Чир касаеися использования спэнов, то какой в этом смысл? Это все равно будет нетипизированная реинтерпетация памяти со всеми вытикающими в случае ошибки. Просто используйте ансэфй и указатели.

Можно еще бинариридером читать и писать, но это будет по медленнее.

Вот здесь
Автор: kaa.python
Дата: 12.09.19
kaa.python забавную пенесометрию. Там народ пишет дрвайверы устройсв в юрезспейсе. Есть микродвайвер, которые умеет выполнять команды и копировать данные в память через DMA. Так вот там те же задачи решаются. Доступ к разделяемой (причем между дровами и юрезспейсом) память. Есть проект на шарпе который оптимизирован фишками то ли 2й, то ли 3й корки.

Там описание и резуьтаты. Шарп показал не плохой результат. Причем код на Шарпе оптимизировали именно сплайсами.
https://github.com/ixy-languages/ixy.cs/blob/1e9de9633b65ce32b4779bd3a2ae95c5a4343a2a/src/IxyDevice.cs#L92
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Структурный доступ к MemoryMappedFile
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.05.21 03:36
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Это не задача, а решение. Не факт, что оптимальное. Какова задача то? Зачем в веб-сервисах доступ к содержимому файла с проекцией в помять?
Затем, чтобы добиться максимальной производительности.
VD>Чир касаеися использования спэнов, то какой в этом смысл? Это все равно будет нетипизированная реинтерпетация памяти со всеми вытикающими в случае ошибки. Просто используйте ансэфй и указатели.
Тоже вариант. Надо посмотреть, какой код проще порождать — со спанами или с указателями. Возможно что и с указателями.
В целом хотелось бы всю unsafe часть изолировать в каком-то уголке, в идеале — в отдельной сборке. А весь основной код пусть будет safe — по крайней мере с арифметикой указателей трахаться не придётся.
VD>Можно еще бинариридером читать и писать, но это будет по медленнее.
Вот помедленнее не надо. Помедленнее можно и из стрима читать.
VD>Вот здесь
Автор: kaa.python
Дата: 12.09.19
kaa.python забавную пенесометрию. Там народ пишет дрвайверы устройсв в юрезспейсе. Есть микродвайвер, которые умеет выполнять команды и копировать данные в память через DMA. Так вот там те же задачи решаются. Доступ к разделяемой (причем между дровами и юрезспейсом) память. Есть проект на шарпе который оптимизирован фишками то ли 2й, то ли 3й корки.

Да, очень похоже.
VD>Там описание и резуьтаты. Шарп показал не плохой результат. Причем код на Шарпе оптимизировали именно сплайсами.
VD>https://github.com/ixy-languages/ixy.cs/blob/1e9de9633b65ce32b4779bd3a2ae95c5a4343a2a/src/IxyDevice.cs#L92
Ну, вот да — в данном примере сплайс позволяет реализовать безопасный аналог bufPtr += numSent.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Структурный доступ к MemoryMappedFile
От: Философ Ад http://vk.com/id10256428
Дата: 14.05.21 11:30
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это не задача, а решение. Не факт, что оптимальное. Какова задача то? Зачем в веб-сервисах доступ к содержимому файла с проекцией в помять?


Проекция в память — это просто удобно. Можно и ReadFile() / WriteFile(), но зачем!?
В веб-сервисах тоже иногда попадаются маппированные на память файлы: движки СУБД именно так и делают.
Вместо того, чтобы вручную заниматься кэшированием и руками записывать изменённые данные значительно удобнее использовать MMF, а всю эту муть переложить на плечи OS.

VD>Чир касаеися использования спэнов, то какой в этом смысл? Это все равно будет нетипизированная реинтерпетация памяти со всеми вытикающими в случае ошибки. Просто используйте ансэфй и указатели.

...
VD>Можно еще бинариридером читать и писать, но это будет по медленнее.

Это вопрос удобства. Ансэйф и BinaryReader — это точно неудобно, я проверял. Это ошибки из-за невнимательности, которых могло бы и не быть.
Значительно удобнее делать Span<T> над указателем, чем доставать и писать что-то с помощью unsafe и BinaryReader'а с BinaryWriter'ом.
Span<T> просто сокращает кол-во тупого однообразного кода. Вот, прикинь: при использовании Span<T> слово offset в коде может даже не понадобиться, даже в комментариях.

PS: Жаль, но мы ограничены поддержкой старых систем. Нам C# 5.0 недоступен, равно как и более старшие версии.
Всё сказанное выше — личное мнение, если не указано обратное.
Re[3]: Структурный доступ к MemoryMappedFile
От: Mystic Artifact  
Дата: 16.05.21 22:35
Оценка: 117 (1)
Здравствуйте, Sinclair, Вы писали:

VD>>Чир касаеися использования спэнов, то какой в этом смысл? Это все равно будет нетипизированная реинтерпетация памяти со всеми вытикающими в случае ошибки. Просто используйте ансэфй и указатели.

S>Тоже вариант. Надо посмотреть, какой код проще порождать — со спанами или с указателями. Возможно что и с указателями.
Порождать кому? Тебе? Тогда это вообще не аргумент (неважно как сложно порождать, лиж бы был желаемый результат).

Порождать код, что со спэнами, что с чистыми указателями — одинаково сложно. Для JIT — разумеется любой лишний тип в коде — это повод призадуматься. Если ты работаешь с blittable структурой данных — то можно её объявить как тип и работать с ней, это может упростить и порождение кода, вместо генерации магических конструкций, как и сам код который будет читать JIT, что безусловно упростит и порождаемый нативный код. Но для не blittable — по моему, что спэн, что ещё что — это одинаково сложно (это по сути сериализация/десериализация или интерпретация данных).

Если код генерируемый — спэн должен появляться только там, где это требует API. Опять таки нужно быть крайне осторожным куда вы подаёте спэны. Вместо увеличения производительности, можно попасть в каком-то абстрактном стриме, что он делает span.ToArray(), а затем Write(array), вместо того что ожидается... Спасибо разработчикам фреймворка которые решили сохранить совместимость таким идиотским образом.

Если же внешних раздражителей нет, или они проверены — тогда однозначно стоит их использовать.

Span — это всё ещё присутствующие проверки на границы, которые JIT возможно не сможет устранить (многие должен смочь). Он постарается устранить Slice но это тоже всё вилами по воде, мягко говоря. Самое главное, для меня — этого точно не произойдет в дебаге. Код с указателями будет почти так же быстре как в релизе так и в дебаге (насколько позволяет фреймворк), но со спэнами — дебаг будет отвратителен. Я знаю, что это частно, не фактор — но, всё таки, не зря же об этом призадумались недавно разработчики VC++ и оптимизации генерации своей ахинеи в дебаге?

Короче говоря — качественный код — не должен видеть этих спэнов вообще, потому, что они никогда не были нужны во фреймворке. Это абслютно идиотский тип (не имея move семантики, он фактически бесполезен, в очень многих случаях). Конечно, он покрывает те, случаи которые он покрывает, и его стоит использовать там, где стоит. Код с ним — в целом лучше. Но, вместе с тем — это эдакий уродец, который позволяет оптимизировать лишь некоторые случаи и сделать вид что мы типа-типобезопасны. Безопасность часто в фреймворке решается совершенно топорно и безальтернативно: например ClientWebSocket проверяет принятое текстовое сообщение на то что это валидный UTF8. Спасибо, дорогие, но это явно не то, что должен делать сокет, в добавок тихонько под капотом, в добавок с API который отдаёт байты, в добавок его об этом не просили.

По моим опытам — работа со Span вполне оправдана, в том плане, что оно просто магически работает, на рантайме который его точно понимает. Я пробовал, иногда оптимизировал одну работу со спэнами на более оптимальную работу со спэнами — и... получал более плохой результат во времени выполнения. Сильно не разбирался почему. Просто оставил тупой вариант, который оказался ещё и более быстрым.

S>Вот помедленнее не надо. Помедленнее можно и из стрима читать.

Неужто нет типов данных с переменной длинной, например, строка? Т.е. что бы телепортировать объект через mmap он же должен там находится? А для этого его туда нужно сериализировать. Большинство (C++) фреймворков, которые обещают zero-cost сериализацию имеют либо абсолютно дибильный интерфейс, либо не являются zero-cost вообще, хотя они об этом нагло заявляют. Я почему-то уверен, что любые короткие сообщения дешевле сериализовать и передать в pipe/mmap, нежели париться. Уверен, потому, что знаю, что так работают все. Опять же — речь о коротких сообщениях. Если (как я понимаю) — ты заранее работаешь с большой структурой данных у которой всё внутри — то вопросов нет.

VD>>Вот здесь
Автор: kaa.python
Дата: 12.09.19
kaa.python забавную пенесометрию. Там народ пишет дрвайверы устройсв в юрезспейсе. Есть микродвайвер, которые умеет выполнять команды и копировать данные в память через DMA. Так вот там те же задачи решаются. Доступ к разделяемой (причем между дровами и юрезспейсом) память. Есть проект на шарпе который оптимизирован фишками то ли 2й, то ли 3й корки.

S>Да, очень похоже.
Это был старый и смешной топик с самого начала. Он лишь показал, что все современные системы имеют монолитное ядро и альтернатив этой архитектуре пока нет (вопреки исследовательским проектам прошлых десятилетий). И ещё, что все серьезные драйвера написаны на C/C++, и может быть Rust. Всё остальное может дать неплохой результат, но, оверхед толком не измерен, и в целом всем и так понятно, что любой райнтайм сверху драйвера — это лишнее, если можно без него. А если можно без него — то можно без него... Слава богу, пока не все сошли с ума, и большинство кода написано на С/C++.

VD>>Там описание и резуьтаты. Шарп показал не плохой результат. Причем код на Шарпе оптимизировали именно сплайсами.

VD>>https://github.com/ixy-languages/ixy.cs/blob/1e9de9633b65ce32b4779bd3a2ae95c5a4343a2a/src/IxyDevice.cs#L92
S>Ну, вот да — в данном примере сплайс позволяет реализовать безопасный аналог bufPtr += numSent.
Имхо, важность этого (в рамках топика) — переоценена, хотя — тебе конечно виднее.


PS: Извинияюсь, ответ, безусловно, запоздалый — на самом деле, это всё просто в некотором смысле вброс с моей стороны. Интересно послушать твои свобственные выводы об этом всём.
Re[4]: Структурный доступ к MemoryMappedFile
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.05.21 02:31
Оценка:
Здравствуйте, Mystic Artifact, Вы писали:
MA> Порождать кому? Тебе? Тогда это вообще не аргумент (неважно как сложно порождать, лиж бы был желаемый результат).
Мне. Ну, простота порождения всё же важна. У меня ресурс не бесконечен — чем меньше писать, тем меньше писать

А так — например, для safe-кода можно породить Expression Tree, а затем просто вызвать не нём Compile. Как только мы начинаем играть с указателями — всё, приехали, порождаем MSIL вручную. Это довольно-таки большой объём работы.

MA> Порождать код, что со спэнами, что с чистыми указателями — одинаково сложно. Для JIT — разумеется любой лишний тип в коде — это повод призадуматься. Если ты работаешь с blittable структурой данных — то можно её объявить как тип и работать с ней, это может упростить и порождение кода, вместо генерации магических конструкций, как и сам код который будет читать JIT, что безусловно упростит и порождаемый нативный код. Но для не blittable — по моему, что спэн, что ещё что — это одинаково сложно (это по сути сериализация/десериализация или интерпретация данных).

MA> Если код генерируемый — спэн должен появляться только там, где это требует API. Опять таки нужно быть крайне осторожным куда вы подаёте спэны. Вместо увеличения производительности, можно попасть в каком-то абстрактном стриме, что он делает span.ToArray(), а затем Write(array), вместо того что ожидается... Спасибо разработчикам фреймворка которые решили сохранить совместимость таким идиотским образом.
MA> Если же внешних раздражителей нет, или они проверены — тогда однозначно стоит их использовать.
Спасибо, очень полезные соображения.

MA> Span — это всё ещё присутствующие проверки на границы, которые JIT возможно не сможет устранить (многие должен смочь). Он постарается устранить Slice но это тоже всё вилами по воде, мягко говоря. Самое главное, для меня — этого точно не произойдет в дебаге. Код с указателями будет почти так же быстре как в релизе так и в дебаге (насколько позволяет фреймворк), но со спэнами — дебаг будет отвратителен. Я знаю, что это частно, не фактор — но, всё таки, не зря же об этом призадумались недавно разработчики VC++ и оптимизации генерации своей ахинеи в дебаге?

А что там за затруднения в дебаге?
Скорее всего, они меня в любом случае не коснутся — Microsoft сделали всё, чтобы код DynamicMethod отлаживать было невозможно, хоть со спанами, хоть без.

MA> Короче говоря — качественный код — не должен видеть этих спэнов вообще, потому, что они никогда не были нужны во фреймворке. Это абслютно идиотский тип (не имея move семантики, он фактически бесполезен, в очень многих случаях). Конечно, он покрывает те, случаи которые он покрывает, и его стоит использовать там, где стоит. Код с ним — в целом лучше. Но, вместе с тем — это эдакий уродец, который позволяет оптимизировать лишь некоторые случаи и сделать вид что мы типа-типобезопасны. Безопасность часто в фреймворке решается совершенно топорно и безальтернативно: например ClientWebSocket проверяет принятое текстовое сообщение на то что это валидный UTF8. Спасибо, дорогие, но это явно не то, что должен делать сокет, в добавок тихонько под капотом, в добавок с API который отдаёт байты, в добавок его об этом не просили.


MA> По моим опытам — работа со Span вполне оправдана, в том плане, что оно просто магически работает, на рантайме который его точно понимает. Я пробовал, иногда оптимизировал одну работу со спэнами на более оптимальную работу со спэнами — и... получал более плохой результат во времени выполнения. Сильно не разбирался почему. Просто оставил тупой вариант, который оказался ещё и более быстрым.


S>>Вот помедленнее не надо. Помедленнее можно и из стрима читать.

MA> Неужто нет типов данных с переменной длинной, например, строка? Т.е. что бы телепортировать объект через mmap он же должен там находится?
Типы данных с переменной длиной будем резать и упаковывать. Пока что идея — в том, чтобы заменять код, написанный в терминах абстрактных типов на код, написанный в терминах сериализованного представления.

S>>А для этого его туда нужно сериализировать. Большинство (C++) фреймворков, которые обещают zero-cost сериализацию имеют либо абсолютно дибильный интерфейс, либо не являются zero-cost вообще, хотя они об этом нагло заявляют. Я почему-то уверен, что любые короткие сообщения дешевле сериализовать и передать в pipe/mmap, нежели париться. Уверен, потому, что знаю, что так работают все. Опять же — речь о коротких сообщениях. Если (как я понимаю) — ты заранее работаешь с большой структурой данных у которой всё внутри — то вопросов нет.

Да, идея как раз в том, чтобы всё было внутри. Вот у нас есть потенциально тяжёлый объект, какой-нибудь User, с парой десятков полей. Хочется иметь возможность выполнять запросы типа where.BirthDate.Year == 1977 & Name.StartsWith("A") без полной десериализации объектов. И даже без десериализации отдельных атрибутов.

MA> Это был старый и смешной топик с самого начала. Он лишь показал, что все современные системы имеют монолитное ядро и альтернатив этой архитектуре пока нет (вопреки исследовательским проектам прошлых десятилетий). И ещё, что все серьезные драйвера написаны на C/C++, и может быть Rust. Всё остальное может дать неплохой результат, но, оверхед толком не измерен, и в целом всем и так понятно, что любой райнтайм сверху драйвера — это лишнее, если можно без него. А если можно без него — то можно без него... Слава богу, пока не все сошли с ума, и большинство кода написано на С/C++.

MA> Имхо, важность этого (в рамках топика) — переоценена, хотя — тебе конечно виднее.


MA> PS: Извинияюсь, ответ, безусловно, запоздалый — на самом деле, это всё просто в некотором смысле вброс с моей стороны. Интересно послушать твои свобственные выводы об этом всём.

Ну, я пока что в каком-то смысле действую наощупь. Идею я выше уже изложил — хочется иметь возможность выполнять объектно-ориентированные запросы без того, чтобы дублировать данные в памяти.
С этой точки зрения все данные делятся на три типа:
1. Данные фиксированного размера. Любые обращения к ним можно заменить на *(pagePtr+recOffset+fieldOffset).
2. Короткие данные переменного размера. Например, строки. Для них мы (очевидно) будем вынуждены хранить префикс длины, и можно на ходу порождать Span<char> для передачи в прикладной код
3. Длинные данные переменного размера. Хранятся как цепочка чанков. Для них придётся делать специальные аналоги для всех операций над "управляемым" типом, который выставлен наружу в API построения запросов.

Пока что так.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.