LINUX.ORG.RU

История изменений

Исправление Deleted, (текущая версия) :

Возможно, вы идёте немного не с той стороны и/или смотрите на процесс не с той высоты.

Просто избавление от копирования в каком-то конкретном месте может породить существенные накладные расходы в другом. Один из антипаттернов - кормить парсер отдельными байтами, а не использовать SIMD (примеры №1, №2).

Однократное копирование может быть очень оправдано, особенно для сбора сообщений («выпрямления» данных), для простой и эффективной их последующей обработки.

В сценариях без user-mode TCP-стека (когда данные копируются из ядра), достаточно неплохо работает вариант кольцевого буфера:

  • Данные принимаются непосредственно в голову буфера, т.е. каждый read() их просто дописывает.
  • Перевод указателя записи из конца буфера в начало происходит на границе сообщения, когда до конца буфера остается места меньше максимального размера сообщения. Таким образом, все сообщения всегда лежат в памяти линейными кусками.
  • Данные передаются на обработку целым куском с хвоста буфера, без копирования. Хвост сдвигается после завершения обработки.
  • Если обработка асинхронная, то для каждого обрабатывающего треда (или отправленного на обработку сообщения), отслеживается свое значение «хвоста», а свободное место в буфере отслеживается по минимальному значению из всех «хвостов» находящихся в обработке. При необходимости можно организовать цепочку кольцевых буферов.

Эта схема даёт 0 лишних копирований, при условии что данные всё равно приходиться вычитывать/копировать из ядра.

Если хочется еще быстрее, то см Seastar.

Исходная версия Deleted, :

Возможно, вы идёте немного не с той стороны и/или смотрите на процесс не с той высоты.

Просто избавление от копирования в каком-то конкретном месте может породить существенные накладные расходы в другом. Один из антипаттернов - кормить парсер отдельными байтами, а не использовать SIMD (примеры №1, №2).

Однократное копирование может быть очень оправдано, особенно для сбора сообщений («выпрямления» данных), для простой и эффективной их последующей обработки.

В сценариях без user-mode TCP-стека (когда данные копируются из ядра), достаточно неплохо работает вариант кольцевого буфера:

  • Данные принимаются непосредственно в голову активного буфера, т.е. каждый read() их просто дописывает.
  • Перевод указателя записи из конца буфера в начало происходит на границе сообщения, когда до конца буфера остается места меньше максимального размера сообщения. Таким образом, все сообщения всегда лежат в памяти линейными кусками.
  • Данные передаются на обработку целым куском с хвоста буфера, без копирования. Хвост сдвигается после завершения обработки.
  • Если обработка асинхронная, то для каждого обрабатывающего треда (или отправленного на обработку сообщения), отслеживается свое значение «хвоста», а свободное место в буфере отслеживается по минимальному значению из всех «хвостов» находящихся в обработке.

Эта схема даёт 0 лишних копирований, при условии что данные всё равно приходиться вычитывать/копировать из ядра.

Если хочется еще быстрее, то см Seastar.