Attoparsec: более простой способ анализа типов данных из Data.Word и Data.Int?
Я сейчас пользуюсь bytestring
а также attoparsec
за сериализацию и десериализацию с уважением в игровом сетевом коде. Я был изначально привлечен к использованию этих библиотек cereal
так как bytestring
дает довольно детальный контроль над строителями, включая полезные стратегии распределения и низкоуровневые приматы. Я подумал, что это будет хороший выбор, так как он обеспечит мое лучшее оснащение для решения любых проблем с задержкой / сборкой мусора, с которыми я могу столкнуться позже в проекте.
И пока bytestring
предоставляет множество комбинаторов для общих типов данных, с которыми можно столкнуться при работе с полями пакетов (в основном это типы, найденные в Data.Word
а также Data.Int
лайк Word16
, Word16
, а также Int8
), Я был разочарован, когда не смог найти никаких дополнительных комбинаторов в attoparsec
, Я что-то пропустил? Могу ли я сделать что-то эквивалентное с помощью предоставленных комбинаторов?
Если это так, что функциональность отсутствует, каков обычный способ добавления этой функциональности? Я, конечно, не первый, кому нужно декодировать подписанные шорты в библиотеке. Есть ли причина, по которой эта функциональность не существует? Есть ли общая библиотека, которую я должен дополнить attoparsec
с чем я не знаю? Или я должен сделать что-то вроде этого:
import Data.Bits
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import qualified Data.Attoparsec.ByteString as Decode
import Data.Int
decodeInt16BE :: Decode.Parser Int16
decodeInt16BE = do
bs <- Decode.take 2
return $! (fromIntegral (bs `B.unsafeIndex` 0) `shiftL` 8) .|.
(fromIntegral (bs `B.unsafeIndex` 1) 1))
Потому что это то, что cereal
а также binary
делать внутренне и то, что я в настоящее время делаю, чтобы получить эту функциональность в настоящее время, но было бы неплохо не использовать специальные небезопасные функции, чтобы сделать то, что bytestring
, cereal
, а также binary
уже предоставляют в своих API.
Что делает большинство людей, когда им нужно заняться Int64
, Int32
, Int16
, Int8
, Word64
, Word32
, а также Word16
с attoparsec в сетевой среде с низкой задержкой?
(NEWBIE NOTE) Здесь есть предположение, которое может быть наивным. Я неявно предполагаю cereal
не быстрее для обработки сетевых пакетов, чем реализации в bytestring
а также attoparsec
, Это предположение возникло из-за просмотра некоторых выступлений на двоичном-serialise-cbor, которые указывают на довольно большое количество распределений, происходящих в cereal
а также binary
благодаря их продолжению подход к кодированию и декодированию двоичных данных в буферах. Я имею дело с сетевыми пакетами, которые часто могут быть закодированы и декодированы довольно простым способом без сохранения состояния со случайным полем, подпрограмма кодирования / декодирования которого зависит от значения ранее увиденного поля. Может быть, мне нужна проверка в реальных условиях, и я использую не те инструменты для работы? Может быть, на самом высоком уровне я ничего не могу сделать, чтобы улучшить свою ситуацию? Предположим, что "не преждевременно оптимизировать" не применимо в этом случае.
1 ответ
Вы должны объяснить более подробно, что вы делаете с пакетами. Большая часть обработки сетевых пакетов не требует обратного отслеживания, поэтому attoparsec несколько избыточен. Кроме того, attoparsec (и двоичный и зерновой) требует, чтобы вы посещали каждый байт пакета. Однако местоположения полей в большинстве сетевых пакетов имеют фиксированные смещения. Таким образом, вы можете "произвольно обращаться" к полям, как только вы изучите заголовок, чтобы определить, какой тип пакета у вас есть.
Я думаю, что вы можете достичь (почти) реализации с нулевым распределением - просто напишите свой алгоритм, как вы делали бы это в C: загрузите ваши пакетные данные в изменяемый распакованный вектор; сохранить смещение к началу текущего пакета; если у вас нет полного пакета в буфере, переместите то, что у вас есть, в начало вектора и заполните остальные новые данные пакета.