TGViewer
Чайник из Юты Чайник из Юты @irrationalthings · 121 subscribers
Post #593 180
Кодеки - тяжело. И это не их вина.

Последние часов 20-30 я работал исключительно над компрессией и декомпрессией. Их было непросто впихнуть. На 40% потому, что я не знал, как. И на 60% - потому что мне активно мешали.

И мешали мне io.Reader с io.Writer.


Нет, идея-то в корне хорошая: унифицируем интерфейс для ввода-вывода. Только вот на деле оказывается жизнь сложнее, чем предполагалось. io.ReadFrom, io.WriteTo - костыли как раз потому, что в какой-то момент внезапно оказалось, что у ридеров и врайтеров могут быть собственные внутренние буфера, из которых данные всё так же прекрасно читаются или пишутся! И даже не всегда нужно иметь лишний буфер-прослойку, чтобы данные между ридером и врайтером перекидывать!!!

Даже для потоковой обработки внезапно io.Reader не таким уж и удобным оказался. Начинаешь мешать ReadByte() (спасибо за непрямой вызов и кучу лишних инструкций ради 8 бит данных!) и io.ReadFull - и это неизбежно. Больше не можешь векторизировать поиск символа (а это неслабо бьёт по перфу). Смешнее только, когда оказывается, что ты вычитал немного того, что тебе уже не принадлежит, и по-хорошему бы их вернуть обратно. Я честно пытался переписать свой парсер, но получалась какая-то исключительная поебота. Оставил, как было: парсер получает сырой массив байт, диспатчит стейт и прыгает на нужную метку, возобновляет работу. Функция на 550 строк и 31 гото, и это работает просто хорошо. Старомодно, на расте невыразимо, но это удобно. Не надо никак изъёбываться с тем, как бы ридер засунуть, особенно в тестах: сунул столько, сколько надо, если хочешь протестировать промежуточный стейт - просто не суёшь ничего больше. Никакого unexpected EOF. И явно уж меньше if err != nil.

Ридер даже концептуально плох. В этом его вины мало, конечно: поскольку нет чего-то на подобии енума из раста, он возвращает ОБА n и err. Часто все сразу по привычке ставят if err != nil, но это неправильно: ридер МОЖЕТ вернуть n > 0 И err != nil. И в семантике чётко написано, что в таком случае, сначала данные должны быть обработаны, а только потом мы можем смотреть на ошибку. Я у себя это эсплуатирую, чтобы на один непрямой вызов меньше делать, но это совершенно неочевидно и далеко не всеми придерживается.

io.Writer ничем не лучше. Это мои компрессоры, как раз, и я с ними имел опыт первоклассного секса. Ебали, к сожалению, меня. Чтобы не стать счастливым владельцем лишнего промежуточного буфера (а это аллокации, при том потенциально регулярные), я молюсь всем Богам на предмет поддержки io.ReaderFrom или io.WriterTo. А худшее - мне пришлось раскроить сериализатор. Потому что компрессору нужно куда-то писать выхлоп, и мне его надо кормить в свой chunked writer. Чтобы без лишних движений байт, я добавил в chunked writer ещё и ReadFrom, что удобно примерно нихуя. Примерно аналогичный метод, но с немного другой логикой. Так в ReadFrom теперь ещё и не совсем понятно, как увеличивать нормально буфер - пришлось лакомиться эвристикой "буфер при чтении был заполнен на >98.64%".

Вишенка на торте - компрессор не закрывает тот врайтер, что я ему передаю. А у меня при закрытии как раз терминальный чанк пишется. То есть, оно всё ещё и чейнится - не чейнится. При том, то, что переданный поток не закрывается - это принято за хорошую практику.

А знаете, как можно было бы сделать лучше?

Сделать, как мой парсер - сунул байты, получил байты. Ну, ещё буфер суёшь, куда тебе результат напихивать. Всё.

И тогда мир оказывается настолько сильно проще! Ты больше не думаешь, где хранить буфер чтения, как бы не забыть про len переданного слайса (объёбывался несколько раз об это), потом ещё обрезать тот слайс до n. И чейнить внезапно оказывается не так уж и сложно: вместо того, чтобы между каждым врайтером держать промежуточный буфер, ты держишь только два! Из одного читает, в другой пишет - а для следующего просто меняем буфера местами. Больше не существует проблемы, которую решал бы io.Copy: ридера больше нет, у тебя на руках сразу массив со всеми данными!

io.Reader и io.Writer - это та вещь, которую я, наверное, ненавижу больше всего в Го. Даже сильнее if err != nil.
More from @irrationalthings
  1. Sep 21, 2026я хрюкнул
  2. Sep 21, 2026гемини
  3. Sep 15, 2026Тот факт, что между нейронками и компрессорами больше общего, чем может показаться - забав…
  4. Sep 15, 2026"Low-Resource" Text Classification: A Parameter-Free Classification Method with Compressor…
  5. Sep 15, 2026Конечно, они сравнивали со средненькими классифицирующими моделями. Там есть пространство…
  6. Sep 15, 2026GZIP наносит ответный удар Вот мы хотим классифицировать текст. Классическая задача для ML…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →