Стендап Сьогодні

Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті

Підписатись на RSS
📢 Канал в Telegram @stendap_sogodni
🦣 @stendap_sogodni@shevtsov.me в Федиверсі

24.02.2024

Водяне охолодження ПК — що воно таке?

В мене вже третій рік ПК працює на водяному охолодженні. Весь цей час збираюся щось написати, отже, сьогодні почну.

Мій ігровий ПК стоїть в зачиненій шафці під телевізором — в режимі HTPC - проте це потужний ігровий компʼютер. З самого початку йому не вистачало охолодження. Скільки вентиляторів не додавай в корпус компʼютера, шафка все одно перетворювалась на духовку. Можна було б придумати повітрообмінник з шафи назовні, але, після довгих роздумів, я все ж вирішив піти з водяною системою.

Що ж, водяне охолодження безперечно здатне перетворити теплові потреби компʼютера на щось абсолютно нове. Я обрав зовнішній радіатор — бо задача була винести тепло за межі шафки. Таке рішення працює абсолютно беззвучно більшість часу, та набагато тихіше звичайного охолодження під час найбільш навантаженої роботи: теплова маса радіатора дає величезну фору будь-якій іншій системі охолодження.

На мою думку, водяне охолодження варто своїх коштів… але кошти підуть немаленькі. Історій про фітинги, які протікають, трубки, які розкладаються, і так далі, достатньо, щоб зрозуміти, що заощаджувати не варто. Навпаки, компоненти від надійних виробників служать довго та абсолютно без проблем. Орієнтовно, я б закладав бюджет на систему у $500 - $1000.

Окрім витрат, доведеться мати базово-просунуті навички в цілій низці галузей. Розбирати компʼютер — очевидно. Але також, зняти радіатор з відеокарти (це зовсім не така типова задача, як з процесора!). Зібрати “сантехніку” та перевірити на протікання. З зовнішньою системою — подовжувати кабелі для вентиляторів. Вішати все це на стіну. А потім ще й налаштувати програмну частину, щоб керувати швидкістю помпи та вентиляторів (бо так, є ще й помпа зі своєю фізикою).

Одним словом, хобі як дороге, так і складне. Але принаймні результат того вартий. По-перше, це красиво та рідкісно. По-друге, дозволяє не згадувати про охолодження навіть у найвибагливіших іграх. Поки на цьому все, подробиці будуть пізніше.


23.02.2024

10 днів зі стохастичним таймтрекером

Вже трохи більше як тиждень користуюся своїм таймтрекером (який паралельно дописую). Коли виправив надсилання сповіщень, то, фактично, MVP вже був готовий. Нагадаю, що на відміну від типового трекера, цей — стохастичний — самостійно опитує (“пінгує”) тебе у випадкові моменти часу — так само як це роблять статистичні профайлери коду. В середньому, раз на 45 хвилин, але на практиці бачив і раз в 3 хвилини, і 3 години без пінгів.

Поки експеримент мені подобається, далі буде.


22.02.2024

Проблема декількох версій залежностей

Є така проблемка в проєктах на Go, що у транзитивних залежностях може бути декілька версій однієї бібліотеки. Ну, наприклад, github.com/redis/go-redis/v9 та github.com/go-redis/redis/v8. Окрім того, що це збільшує розмір програми (та хто його лічить?) - є й ризик помилки.

(До речі, в Go предивна система версій модулів. Взагалі в Go модуль це тека. Ніякої “збірки” у .gem, .jar, чи навіть .zip немає. Назва модуля дорівнює його URL в Git. А наступна несумісна версія модуля створюється… не в теці v2, як може це здатись, а у гілці з назвою v2. При цьому назва модуля залишається такою самою. Мені доводилося це робити з нашою бібліотекою go-global, коли вона переїхала з AWS SDK v1 на AWS SDK v2, який цій системі не слідує.)

Коли ти оперуєш типами з пакета, легко помітити різницю між версіями, бо вони є несумісними. Але не всі операції потребують типів. Наприклад, константи помилок з різних версій пакета не проходитимуть перевірку на рівність. Та й інші нетипізовані константи. А ще глобальні налаштування на кшталт хуків — вони теж можуть піти не туди, куди треба.

Одним словом, коли значення, які за всією логікою мають збігатись, все ж розрізняються, перше, що спадає мені на думку — перевірити версії модулів.

Така сама тільки гірше проблема в JavaScript - бо там типи не допомагають, а залежностей експоненційно більше.


21.02.2024

Пара неочевидних ідіом у SwiftUI

Взагалі, помітив, що останнім часом багато натрапляю на прості, ідіоматичні рішення замість своїх ускладнених за браком знань. Вчусь, напевно. Бо буває, що ідіоматичний код очевидний, а буває навпаки, перелопатиш половину Інтернету, але на жаль не за тими пошуковими запитами.


20.02.2024

Операції з часом в OpenSearch

Поступово дізнаюся нові можливості OpenSearch (та ElasticSearch), які, хоч і базові, але чомусь на поверхні не лежать. Сьогодні — про те, що дати набагато гнучкіше, ніж я собі думав.

Взагалі OpenSearch зберігає дати як числа. Проте, як я розумію з коду, різниця в індексації є: як я писав, числа OpenSearch індексує деревом множин, щоб швидше шукати за діапазоном. Для дат ці множини будуються не аби як, а за одиницями часу: хвилинами, годинами й так далі: ось код. Звісно, це саме те, чого ми хочемо від пошуку за часом.

Але це таке, знати не потрібно. А що варто знати, так це те, що час можна вказати зі скругленням до потрібної одиниці. Наприклад, потрібно мені знайти записи за останній тиждень. Як вказати верхню межу? Відома проблема, що просто датою не можна — відбитки часу за останню дату будуть технічно більші за дату без часу. Тому можна вдаватись до хаків: написати 23:59:59 (і втратити відбитки за останню хвилину!), чи зробити строго менше наступної дати. Проте в OpenSearch можна просто зробити запит зі скругленням до дня:

{
  "range": {
    "timestamp": {
      "gte": "2024-02-12||/d",
      "lte": "2024-02-18||/d"
    }
  }
}

(Ба більше, в цьому прикладі можна було б скруглити до тижня та ще спростити собі роботу.)

Та й повертати значення дати можна відразу в такому форматі, як нам потрібно: для документів з пошуку є опція docvalue_fields (дивна назва), а для агрегацій за датою просто format. Трохи незвично таке робити в базі, бо я звик, що бібліотека-клієнт віддає обʼєкти дати, з якими вже робиш що хочеш — проте за відсутністю такої бібліотеки дуже зручно.


19.02.2024

Вебсервери на Ruby: чим вони відрізняються

Хотів в завершення теми про рівночасне програмування пройтися по серверах на Ruby та порівняти їх. Виявилось… що тема трохи застаріла. Памʼятаю часи, коли вибір сервера був гарячою темою — років з 10, а то й 15 тому. Але наразі все стабільно (та й Ruby перестав бути такою гарячою темою.) Отже.

НДНЧ: Puma - це все, що тобі потрібно.


18.02.2024

Рівночасне та паралельне програмування

Зі всіма цими написами про рівночасність та паралельність легко заплутатись. Що я не раз зустрічав у плануванні алгоритмів та підходів. (До речі, правильний український термін - рівночасність, а не одночасність, як я писав раніше. Жодний з них не є самоочевидним, на жаль.)

Рівночасність (concurrency) - це здатність програми утримувати декілька потоків виконання. Побутова аналогія: я можу “рівночасно” робити роботу та збирати Лего. Поки працюю — Лего не збирається. Потім припиняю роботу — сідаю за конструктор. Як робота, так і конструктор продовжуються з того місця, де я зупинився. Це рівночасні процеси. Але я не можу збирати в той самий час, як працюю. Це вже…

Паралелізм (parallelism) - це здатність виконувати більш ніж один потік у момент часу. Паралелізм потребує, в першу чергу, більше одного ядра процесора. Бо тут криється головний нюанс: йдеться про виконання процесором, не очікування на зовнішні ресурси. Очікування на ресурси є апріорі “паралельним”, навіть коли “паралелізм” нам недоступний — наприклад, з одним ядром процесора чи в мові з GIL.

Якщо продовжити аналогію, то поки замовлений конструктор тільки їде поштою, нічого не заважає мені працювати. А ось зібрати його в той самий час як я працюю, може тільки дружина — це вже справжній паралелізм!

Хиба в плануванні рівночасних програм полягає в відсутності розрізнення роботи процесора та вводу/виводу. Коли програма здебільшого зайнята вводом/виводом — здатність до паралелізму не важлива — ані за властивостями мови, ані за кількістю ядер процесора. А якщо потрібно прискорити обчислення — тоді треба шукати паралелізм.


17.02.2024

Навіщо потрібен GIL (глобальне блокування інтерпретатору)

Ще трохи розбирався з паралельним виконанням в Ruby. Хотів зрозуміти, чому в Ruby є GIL. Дізнався, що нічого в характері мови не потребує глобального блокування як такого. GIL це архітектурне рішення.

В будь-якій програмі будь-якою мовою з одночасністю виникають проблеми псування памʼяті через паралельний доступ. Байдуже, динамічна мова, чи інтерпретована, чи статична, чи використовує віртуальну машину. Щоб злагодити доступ, використовують різні механізми блокування. Навіть якщо код застосунку блокувань не містить, то системні підпрограми обовʼязково.

GIL - це найпростіша форма блокування. З GIL можна практично не згадувати про паралельний доступ в коді інтерпретатора. Проте, на жаль, мова втрачає всяку можливість паралельної роботи взагалі. Це не так страшно насправді оскільки головною задачею одночасного виконання є ефективна обробка вводу-виводу, а не паралельне використання ядер процесора.

Чому розробники інтерпретаторів йшли на такий компроміс? Як я розумію, причина суто історична. Інтерпретатори з GIL (Ruby MRI, CPython) зʼявилися ще у девʼяності, коли багатоядерних процесорів взагалі не існувало. Пізніше додати в код систему детальних блокувань практично нереально, тому й зробили просте глобальне блокування.

А є й популярні мови PHP та JavaScript - які взагалі не мають моделі паралельного виконання. Немає там можливості створити потік. І це їм не заважає бути одними з найпоширеніших мов на сервері.


16.02.2024

TimeTag - інтервал впевненості

Перейшов потроху зі збору даних (який працює досить непогано!) до аналізу. Тут не все просто: оскільки тайм трекер питає тебе в випадкові моменти, то не можна просто підрахувати розподіл результатів. На додаток маємо обчислити інтервал впевненості: “цією міткою відмічено 2 години плюс мінус 30 хвилин”.

Шляхом реверс-інжинірінгу алгоритму та пошуку в інтернеті (я в статистиці нічого не розумію) знайшов купу різних формул. Проблема тут така, що одні терміни спираються на інші, і так далі, та часто взагалі не зрозуміло, чи рухаєшся в правильному напрямку.

Нарешті, знайшов як сформулювати питання та знайшов таке саме на StackOverflow. Яке ж було моє здивування, коли помітив, що питання поставив оригінальний автор алгоритму! На щастя, він знайшов правильну формулу для інтервалу впевненості, та ще й саме для релевантної задачі.

Є тільки одна маленька проблема… формула використовує обернену гамма-функцію (TIL.) У автора вона написана в пакеті Mathematica. А як мені обчислити таку в коді? Спочатку знайшов npm-пакет, та навіть почав перекладати на Swift. Проте, перекладати складні математичні функції без розуміння ну дуже ризиковано — там добра тисяча рядків коду. Та й де гарантії, що автор невідомого NPM-пакету не встиг вже наробити помилок?

Тоді згадав про найстаріший трюк математичного програмування — обчислення за таблицею. Все, що мені потрібно — це знати значення оберненої гамма-функції для можливих значень кількості моментів з міткою. А значення можна взяти в Mathematica, точніше, у Wolfram Alpha. Причому відразу масивом — безплатно дає до 2 тисяч значень за раз, більше не проходить за часом:

InverseGammaRegularized[Range[8001,10000],0.025]

Для 10000 моментів інтервал впевненості дорівнює 4% - я думаю, що похибка “вимірювання” буде більша, тож немає сенсу збільшувати математичну точність. А зберегти в коді 20000 значень незрівнянно легше (та швидше у виконанні!), ніж обчислювати їх. Колись таким чином ігри зберігали тригонометричні функції та таке інше.


15.02.2024

Виправив підписку на Twitter через RSS

Як я дуже давно писав, для стеження за джерелами інформації використовую RSSHub. От є тільки невеличка проблемка — з Twitter останнім часом щось… трохи сталося та стрічки вже з пів року не працювали. Нарешті виправив.

Взагалі зараз для отримання постів потрібна авторизація. Але й з нею є різні дивні обмеження. Через це, наприклад, відомий альтернативний фронтенд Nitter, скоріше за все, припиняє існування.

Останнім часом Nitter використовував ось такий кривий хак: після встановлення застосунку Twitter на Android тобі видавався тимчасовий гостьовий акаунт. Ось цей акаунт вони й використовували — в сукупності з клієнтськими ключами того ж застосунку — для доступу через внутрішній API, на котрому побудовані офіційні застосунки. Такі відчайдушні рішення довго не тривають — особливо на публічному сервісі, яким був Nitter. Так і стало — гостьові акаунти більше не видають.

А для моєї особистої копії RSSHub поки працює такий саме підхід, тільки вже з особистим акаунтом. Для того дехто написав скрипт, яким можна “зайти в застосунок Android” та отримати ключі. Навіть не потрібно створювати свій проєкт для доступу до API. Далі ключі додаються в RSSHub та — о диво — стрічки знову працюють. Тільки чи надовго?