windows terminal

неплохо. меня раньше от PS отгораживало, что он грузится дольше cmd или conemu+clink, в windows terminal всё быстро + после накидки привычных биндингов + полупрозрачности фона - вообще удобно стало, хотя, конечно PS пока не очень привычен.

Да и по ущущениям быстрее conemu работает.

Rust - опять #2

Для предыдущей проблемы пришлось патчить hyper. Справился - отлично, можно идти дальше, пару новых строчек кода (безопасного) и программа _после компиляции_ кидает ошибку на 15 страниц. В чём дело? Вероятно, простая и безопасная библиотка по выводу progress-bar'а на экран запуталась в своих безопасных Mutex'ах в самом безопасном на свете языке.

Rust - опять

Есть у меня pet-проект, который тянется уже больше года и, постепенно, подходит к финальному аккорду.

В какой-то момент было решено изменить способ хранения данных у клиента на простые файлы => понадобилась некая скачивался данных из базы для этого, всё работало почти отлично - данные качались чанк за чанком, прогрес-бар показывал сколько осталось. Кроме одного - данные не сжаты и их много - отдавать потоком - остаться без Content-Length - пользователь будет в неведении сколько осталось. Сжимать сразу много - пользователю очень долго ждать этого Content-Length.

Было решено просто - собирать по 1000, сжимать и отдавать - всё опять же работало, но что-то было странно - иногда некоторые чанки приходили битыми. Посмотрев на пакеты стало понятно - что пакеты нормальные, а вот способ их обработки у hyper такой - если chunk не влезает в буффер (8kb) - то выдавать chunk с тем что есть, а остальное - как будто это другой чанк. Насколько это корректное поведение не берусь судить, возможно и верное. Хотел было переехать на web-sockets, и тут, actix-web, казавшийся нормальным в качестве http показал, что структура для ws должна делаться так: Client<SinkWrite<Message, SplitSink<Framed<T, Codec>, Message>>> - просто же, и удобно - все кишки видны, а то мало ли нужно будет из client.0.0.0 извлечь codec.

Дальше надо описать актор, потом Handler, потом ещё StreamHandler, в который надо передать mut-контекст этого клиента, после чего из него дёргать руками методы типа ctx.0.write или обёртки. Но это не заработает со фьючовыми стримами, потому как при создании этого клиента - надо вызвать мутабельный add_stream на нём, в котором связать Stream и контекст - видимо иначе он не будет знать что надо дёргать этот handler, при этом, даже если совершить все эти действия - это только для обработки выходного потока из stream - как писать в него из другого стрима без своего impl Stream поверх - останется загадкой.

В общем, от такого юзать ws как-то расхотелось. Знающие люди говорили, что надо просто накрутить length_delimited кодек на чанки http и у меня будут нормальные фреймы данных - попробую в эту сторону. Кодеки работают через ASyncRead, а hyper/actix выдают Stream<Item=Vec<u8>> - хотя в общем-то понятно, что результат их работы в этом случае одинаков, и только в futures 0.3 сделали метод into_async_read() который позволяет одну абстракцию преобразовывать в другую => можно просто писать в codec - ура!, но нет, не ура, tokio 0.2 почему-то имеет свои ASyncRead, которые почему-то не совместимы с futures 0.3, а другие мне не подойдут. Есть некий клей - compat, но, бывалые люди, сказали что всё же _надёжнее разобрать байты руками_, чем пробраться через страницу какой-нибудь ошибки, которую покажет что compat(), без compat() ошибки и так по пол-страницы и не сильно проще читать.

Вернёмся к тому, что я никак не ожидал - что я могу застрять на несколько недель на простой скачивалке файла чанками, a раст, в очередной раз, как говорится, пробивает дно в производительности сроков написания чего-то отличного от примеров из папки examples (кстати и это часто не собирается). И у меня много таких случаев о которых можно было бы рассказать не меньше - но первый раз, когда решил написать.

Rust, рефакторинг

Всё работало, вроде неплохо, пока не подключил extern crate pyo3. Естественно всё просто в Rust быть не может - не могу обернуть структуру с лайфтаймами макросами pyo3 => начался глобальный рефакториг по вычищению от лайфтаймов довольно центральной структуры => всё замазывается толстым слоем Rc/Arc/RefCell, настолько толстым, что хотется начать писать на Swift.

что-то типа такого:
self.borrow().control.borrow().stats.borrow_mut().counter += 1;


какой приятный код :(
При этом это по сути убивает всю lifetime концепцию - так как каждый borrow - это твой личный и ручной контроль поверх раста.

teamviewer => anydesk

teamviewer меня заблокировал якобы за коммерческое использования, хотя всё что я сделал - поменял полиси телеметрии на компе. В ответ на запрос вернуть всё назад они ответели что не видят для этого причин, но если очень надо, то я должен выслать расписку, паспорта и фотографии, что не то что сложно, но как-то немного противно.

Переехал на anydesk:
- удивительно, но по локалке он намного быстрее.
- интерфейс немного более багованный - иногда на полном экране артефакты.
- мобильное приложение тоже не очень удобное.

teamviewer и screenconnect

Однозначно побеждает первый - когда я соединяюсь между компьютерами в одной сети - то можно даже youtube нормально смотреть. screenconnect гораздо медленнее, и похоже не умееть напрямую соединяться.

ubuntu => alpine linux => ubuntu

Думал, о том, что ubuntu немного жирновата, посмотрел вокруг и наткнулся на alpine в образах scaleway, тут же поднял сервер. По-началу действительно немного меньше, но как только начинаешь всё ставить - то оно быстро вырастает до почти убунтувских размеров.

Собрал всё под неё, посмотрел на глаз сколько жрёт процессора - на глаз меньше прилично, смотрю дальше, ба! , да оказывается другой проц на scaleway поднялся. Поднял ещё одну убунту - замерял - alpine кажется немного больше жрёт cpu на той же задаче (я конечно понимаю точность сравнения top'ом :) ). Из приятного - всё кажется более простым и арчеподобным, пакеты аналогично - mongodb и rust из коробки довольно свежие. Пока не наткнулся на это: http://www.etalabs.net/compare_libcs.html , а потом ещё какие-то косяки с безопастностью и с производительностью тоже (причём свежие) нагуглились, ну и ну его решил, - опять убунту на scaleway поднял.

coinbase-pro-rs

Запилил API на расте для работы с coinbase: https://crates.io/crates/coinbase-pro-rs

поддерживает в том числе futures и websocket.
Ордербук пока положил отдельно - в связке он мне пока не нужен - но как только, так сразу его затащу внутрь.

Молча ненавижу питон - банально сделать moving-window на 100 x 2000значений и компьютер превращается в калькулятор, под pypy не собирается.

Rust. The Computer Language Benchmarks Game

Что-то где-то обновилось, пересчиталось, и я, неожиданно для себя вылез на первое место по Rust в k-nucleotide benchmark, причём даже с небольшим заделом:

https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/knucleotide.html

1. C++ g++ #2
3.66 155,956 1624 11.16 70% 98% 70% 68%
2. C gcc
5.07 130,008 1506 15.25 88% 84% 58% 73%
3. C# .NET Core #9
5.29 186,892 2574 17.90 96% 67% 93% 84%
4. Rust #8
5.76 135,728 1900 16.77 84% 94% 49% 65%
5. Rust #4
6.07 137,948 1749 18.11 51% 81% 78% 90%

C++ по-прежнему кажется недостежимым - чтобы посоревноваться за первое - нужен быстрый hashmap со специализацией по типам.

Продолжаю бенчмаркать

Итого за три дня написан ~ одинаковый функционал на python и type-script, который уже давно был реализован на расте. Задача довольно примитивная, но зато из реальности:
1) есть какое-то количество данных.
2) строим 100 минутных свечей (по сути только close) _от_текущего_тика_ (есть ли в этом смысл - это отдельная тема)
3) загоняем в ML
3) делаем #2 и #3 проигрывая исторические данные в цикле, например от 0 до 2000 для начала.

Итого:

PYTHON: Изначально всё было написано на питоне и pandas, который вроде как раз предназначен для подобных группировок, однако именно группировку он выполнял настолько долго, что я это даже не мерял - больше минуты.
TS: Написал это же на TS с использованием data-forge - картина аналогичная - с точки зрения производительности всё настолько печально, что даже замерять нету смысла.
TS#2: Выкинул data-forge, итого - TS разогнался до ~20 секунд.
PYTHON#2: Выкинул pandas и переписал всё исключительно цифрами (заодно время тоже, до этого это был datetime) на numpy - получилось всего 0.5sec.
TS#3: Выкинул модуль moment.js и TS тут же разогнался с ~20 до ~2 секунд, что в целом неплохо, учитывая что никаких биндингов.

На данном этапе python победил своим numpy, хотя на тот момент TS нравился больше.

Следующий этап - решил подключить ML, ведь каждый хочет с этим поиграться.
PYTHON#3: 20Mb модель он считает ~13ms.
TS#4: Похоже на то что keras.js это имплементация ML без всяких биндингов - следовательно всё считается на ванильном JS. И, оказалось, что в таком виде, 20Mb модель он предиктит 900ms, что при любом раскладе неприемлемо. Учитывая, что он это делает асинхронно в одном потоке, то, если продолжать слать данные, цифры модели вообще могут начать приходить с большим >30сек. опозданием.

Некий, наверное очевидный, вывод:

Python тормоз, на нём писать нельзя, но можно использовать волшебный numpy, если задача хоть как-то в него заходит.

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

Итого: для склейки оставляю питон.