История изменений
Исправление Deleted, (текущая версия) :
Возможно, вы идёте немного не с той стороны и/или смотрите на процесс не с той высоты.
Просто избавление от копирования в каком-то конкретном месте может породить существенные накладные расходы в другом. Один из антипаттернов - кормить парсер отдельными байтами, а не использовать SIMD (примеры №1, №2).
Однократное копирование может быть очень оправдано, особенно для сбора сообщений («выпрямления» данных), для простой и эффективной их последующей обработки.
В сценариях без user-mode TCP-стека (когда данные копируются из ядра), достаточно неплохо работает вариант кольцевого буфера:
- Данные принимаются непосредственно в голову буфера, т.е. каждый read() их просто дописывает.
- Перевод указателя записи из конца буфера в начало происходит на границе сообщения, когда до конца буфера остается места меньше максимального размера сообщения. Таким образом, все сообщения всегда лежат в памяти линейными кусками.
- Данные передаются на обработку целым куском с хвоста буфера, без копирования. Хвост сдвигается после завершения обработки.
- Если обработка асинхронная, то для каждого обрабатывающего треда (или отправленного на обработку сообщения), отслеживается свое значение «хвоста», а свободное место в буфере отслеживается по минимальному значению из всех «хвостов» находящихся в обработке. При необходимости можно организовать цепочку кольцевых буферов.
Эта схема даёт 0 лишних копирований, при условии что данные всё равно приходиться вычитывать/копировать из ядра.
Если хочется еще быстрее, то см Seastar.
Исходная версия Deleted, :
Возможно, вы идёте немного не с той стороны и/или смотрите на процесс не с той высоты.
Просто избавление от копирования в каком-то конкретном месте может породить существенные накладные расходы в другом. Один из антипаттернов - кормить парсер отдельными байтами, а не использовать SIMD (примеры №1, №2).
Однократное копирование может быть очень оправдано, особенно для сбора сообщений («выпрямления» данных), для простой и эффективной их последующей обработки.
В сценариях без user-mode TCP-стека (когда данные копируются из ядра), достаточно неплохо работает вариант кольцевого буфера:
- Данные принимаются непосредственно в голову активного буфера, т.е. каждый read() их просто дописывает.
- Перевод указателя записи из конца буфера в начало происходит на границе сообщения, когда до конца буфера остается места меньше максимального размера сообщения. Таким образом, все сообщения всегда лежат в памяти линейными кусками.
- Данные передаются на обработку целым куском с хвоста буфера, без копирования. Хвост сдвигается после завершения обработки.
- Если обработка асинхронная, то для каждого обрабатывающего треда (или отправленного на обработку сообщения), отслеживается свое значение «хвоста», а свободное место в буфере отслеживается по минимальному значению из всех «хвостов» находящихся в обработке.
Эта схема даёт 0 лишних копирований, при условии что данные всё равно приходиться вычитывать/копировать из ядра.
Если хочется еще быстрее, то см Seastar.