DevNotes Live
6 subscribers
84.2K photos
12K videos
195 files
35.4K links
Автоматический агрегатор IT ресурсов в Telegram (@devnotes_robot)
Информация: https://t.me/devnotes_live/121
Download Telegram
Стратегии борьбы с throttle в event loop при работе с Native Addons и FFI через worker_threads

Node.js живёт на одном потоке — это знают все. Но когда в дело вступают Native Addons (napi, C++ модули) и FFI (Foreign Function Interface), event loop может неожиданно "зависнуть". Даже если ты используешь worker_threads, throttle всё равно случается. Почему? Потому что нативные вызовы не всегда изолируются полностью. Блокирующий системный вызов в аддоне может зацепить libuv thread pool или V8, и основной поток начинает тормозить.

FFI тут особенно неприятен. Библиотеки типа ffi-napi или koffi вызывают shared library синхронно — event loop просто стоит и ждёт, пока вызов вернётся. Все остальные задачи замораживаются.

Что с этим делать?

1. Вынос в dedicated worker.
Создаёшь отдельный worker, грузишь туда аддон, общаешься через MessageChannel. Главное — не передавай shared memory без синхронизации, если аддон не thread-safe.

const { Worker } = require('worker_threads');
const worker = new Worker('./native-worker.js', { workerData: {} });
worker.postMessage({ task: 'heavyCalc', data: [1, 2, 3] });
worker.on('message', result => console.log('Результат:', result));


Внутри worker:
const { parentPort } = require('worker_threads');
const nativeAddon = require('native-addon');
parentPort.on('message', msg => {
const result = nativeAddon.heavySync(msg.data);
parentPort.postMessage(result);
});


2. Асинхронные API для аддонов.
Если пишешь аддон сам — используй n-api async work (napi_create_async_work). Для FFI — заворачивай вызовы в setImmediate или setTimeout с нулевой задержкой. Это даёт event loop шанс обработать другие задачи.

3. Пул worker'ов с очередью.
Задачи распределяются, и один тяжёлый вызов не может монополизировать все ресурсы. Стандартный паттерн — берёшь задачу из очереди, отдаёшь свободному воркеру.

4. Atomics и SharedArrayBuffer.
Блокировка без захвата event loop. Но требует поддержки SharedArrayBuffer и аккуратной реализации.

5. Мониторинг.
Замеряй время вызовов через process.hrtime.bigint() или performance.now(). Если вызов длится дольше 50ms — это красный флаг. Логируй и переключай на worker.

Коротко:
- worker_threads — база, но не панацея.
- Для своих аддонов — async n-api.
- Для FFI — пулы и очереди.

Вывод:
Изоляция нативных вызовов через worker_threads с асинхронными API и мониторингом — единственный способ избежать throttling event loop в production.
Forwarded from ai.dot(ufna, dev)
Индустриальные обсуждения во многих чатиках выглядят именно так.

Независимо от темы обсуждения.
Forwarded from Andrey
Если чуть пролить аналитику, то длинный ответ будет такой:

Из железа у тебя прям щас есть выбор из:

1. Малый компьют с дохера объёма (370/395/спарки/макбуки/мини/студио/нэйм ит);
2. Средний компьют с мало объёма (3090/4090/b60/b70/7900/9700/нэйм ит);
3. Толстый компьют с дохера объёма (PRO6000/A100/H100/H200/MI250/нэйм ит).

Что отсутствует? Всё верно - средний компьют с дохера объема. Условно говоря, что-то типа RTX4090 на 64гб за недорого. На рынке ровно ничего подобного нет. И вот это довольно интересный момент, потому что РОВНО ТАКАЯ железка всем и нужна в массовом секторе имхо. В какой-то степени я даже удивлён, что всё ещё никто ничего подобного не предлагает, потому что отрывали бы с руками кмк.

Докидываем сюда мультипликатор веселья в виде охуевших цен не разное и всё становится ещё интереснее.

Но допустим, что такая железка у нас есть. Вопрос теперь не менее интересный: а что в неё грузить?

Если говорить про квантованные модели, то у тебя есть:
1. Квен/гемини 27B/31B под 24-32Гб;
2. Целый ворох устаревших на 3-4 поколения моделей типа 70B/120b для 48-64гб;
3. Весь прочий жир типа 0.3T-1T++ моделей, для чего надо 250-300++ Гб.

Что отсутствует? Всё верно - что-то между 2 и 3. Тупо нет и пока не предвидится хороших, качественных моделек такого объёма. Условно говоря, у тебя до сих пор нет какого-нибудь "Qwen 3.6 Coder Next", который при своих 80B как раз влезал в 48 гиговые карточки. То есть, условная 120-ка должна без проблем влезать в 64гб. Но такой модельки сука нет, а всё остальное в подобном типоразмере - либо старое говно, либо не сильно лучше младших квенов/гемини 27B/31B, пусть даже и тоже недавно вышли.

И вот она та самая жопа из первого абзаца - нет средней руки железки и нет средней руки модельки. В итоге либо ты сидишь на 24/48гб и юзаешь условный квен 27б, либо ты въёбываешь пятизнак грина в систему, собирая кластерок из пары PRO 6000, либо ты собираешь бюджет из четырёх-шести-восьми B70 и и втыкаешь туда что-нибудь интересное о 200+ гигах

Всё остальное будет полумерами и постоянным примирением с чем-то имхо. Ну типа, тот же Spark при всей своей пиздатости крайне плохо работает с dense модельками >20B или просто с любыми, где надо жирный компьют, потому что как бы а что вы хотите от такой малышки в коробке из-под конфет. Тот же мистраль медиум там выдаёт ~7 токенов, если мне память не изменяет. Это смешно. Я думаю, ты и сам на клавиатуре с такой же скоростью можешь печатать. :D

Собственно, в подтверждение всего вышесказанного можно процедить тот же реддит и увидеть, что публика там так и делится:
1. Пацаны с 24-32Gb, которые юзают квены/гемини 27б/31б;
2. Те же пацаны, но с несколькими видяхами на 48-96гб, которые юзают либо то же самое на жирных квантах и бОльших контекстах, либо что-то типа старого кодер некста;
3. Пацаны на ламбо с несколькими RTX6000, H200 и прочие подобные ребята из гугла, которым пойти пощупать новый GLM 5.2 на полтора терабайта - как воды попить.

Как видим, пропасть между 1-2 и 3 не заполнена ничем. Отвечая на незаданный вопрос "какого хуя" мысль такая: потому что ровно здесь и кроется sweet spot, который потенциально может закопать весь коммерс по предоставлению облачных решений. Те, что поменьше, угрозы не представляют, а тех, что побольше - слишком мало, чтобы угрожать. Но дай ты людям за недорого то же Qwen3.6 27B, только умноженный на пять или десять, и в целом всё, досвидос, облачка можно закрывать, клиентов у вас не будет. Примерно точно так же в своё время рендер-фермы сдохли - видяхи стали достаточно жирными, чтобы ребята могли у себя дома вменяемо рендерить, а большинству студий достаточно 6-10 на ферме и всё это за копейки.
Forwarded from Daily Coding 🔥
🛠 Buefy - легкий фреймворк UI для Vue.js построен с использованием популярного элемента на основе CSS библиотека Бульма. В ней есть все составляющие типичного веб-приложения должен в том числе динамические элементы, как модели, тосты и уведомления, что позволяет разработчикам быстро добавлять элементы пользовательского интерфейса в своих проектах Vue.js .

🌍 Сайт

Daily Coding #инструменты #Vue & Max
Diagnostics Channel: Загляни внутрь Node.js в production без console.log и перезаливок

Когда приложение падает в production, а логи пусты - начинается классика: залипаешь в терминал с console.log, комментируешь половину кода и перезаливаешь. Но у Node.js есть встроенный механизм для подписки на внутренние события движка и модулей без правки исходников. Называется diagnostics_channel.

Что за зверь?
Модуль diagnostics_channel даёт каналы, именуемые по схеме модуль.событие.подсобытие. Через них V8, libuv и сам Node.js эмитят структурированные данные о внутренних операциях. Подписаться можно без правки кода приложения - просто инициализируешь слушателя в отдельном файле и подключаешь через флаг --require.

Где выстрелит?
- Утечки HTTP-соединений - канал http.client.request.create
- HTTP/2 сессии и их жизненный цикл
- Работа DNS-резолвера dns
- Создание и завершение Worker Threads
- Зависания событийного цикла - канал tick

Пример: ловим утечки HTTP-соединений
const diagnosticsChannel = require('diagnostics_channel');

const clientRequestChannel = diagnosticsChannel.channel('http.client.request.create');
clientRequestChannel.subscribe(({ request, socket }) => {
const startTime = Date.now();

request.on('response', (res) => {
console.log(Request to ${request.hostname} completed (${Date.now() - startTime}ms));
});

socket.on('close', () => {
if (Date.now() - startTime > 5000) {
console.warn(Long-lived socket detected: ${socket.remotePort});
}
});
});


Кладёшь этот код в diagnostics.js, запускаешь с флагом node --require ./diagnostics.js app.js - и никаких изменений в исходниках приложения.

Как тащить в production?
- Условный require: NODE_DEBUG_DIAGNOSTICS=1 node app.js с проверкой в коде
- Или динамически подключай по process.env при старте, чтобы не плодить лишние подписки
- Только помни: подписка - синхронная операция. Не делай внутри тяжёлых вычислений или блокирующих I/O, иначе забьёшь event loop и ухудшишь производительность

Вывод:
Diagnostics Channel позволяет заглянуть внутрь Node.js в реальном времени под нагрузкой, чтобы поймать утечки и задержки до того, как они уронят production, причём без единой правки кода приложения.
Media is too big
VIEW IN TELEGRAM
Vector Archects - Corporate webse
https://.com/shots/22571057-Vector-Archects-Corporate-webse
Подборка интересных баннеров для вашего вдохновения.

💛 Дизайн-Культура
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from ai.dot(ufna, dev)
А это вы видели? Загружаем модельку вам прямо в браузер!

https://huggingface.co/spaces/webml-community/gemma-4-webgpu-kernels
Forwarded from Daily Coding 🔥
Погрузитесь в ИТ за 5 дней и получите доступ к высокооплачиваемым вакансиям!

Бесплатный короткий курс для тех, кто хочет не просто понять, чем занимаются айтишники, но и получить реальный опыт работы с ИТ‑системами.

Всего за 5 дней вы освоите ключевые компоненты ИТ‑сферы, разберёте 6 профессий и получите возможность выйти на зарплату 150–250 тыс.

Курс полностью практический. 8 мини‑проектов с реальными задачами, где вы научитесь: писать код, работать с инфраструктурой, разбираться в сетях, облаке и защите данных.

Подойдёт новичкам и тем, кто уже в ИТ. Количество мест ограничено — регистрируйтесь по ссылке и начинайте практику.

Реклама. Информация о рекламодателе по ссылкам в посте.
Forwarded from Daily Coding 🔥
📖Collaborative Software Design
🖋Baas-Schwegler Kenny, Van Kelle Evelyn, Verschatse Gien 2025

В книге «Совместное проектирование программного обеспечения» вы познакомитесь с принципами, методами и инструментами, способствующими безопасному общению при выявлении бизнес-проблем, формализации требований и реализации программного проекта. В ней рассказывается о таких признанных инструментах совместного моделирования, как «штурм событий», «составление примеров», «составление карт Уордли» и «сторителлинг предметной области», а также о уникальных подходах к управлению когнитивными искажениями, конфликтами и организационной иерархией. Независимо от того, являетесь ли вы заинтересованной стороной в бизнесе, техническим специалистом или профессиональным координатором, вы научитесь слышать всех участников процесса и извлекать пользу из их вклада.

💾 Скачать книгу

Daily Coding #книги #архитектура & Max
Event Loop Lag при тысячах setTimeout: как очередь таймеров убивает latency в production

Когда на сервере больше 1000 активных setTimeout или setInterval, latency неожиданно растет, I/O начинает тормозить, а пользователи жалуются на задержки. Многие разработчики считают, что таймеры безвредны, но на практике их перебор в одной фазе event loop блокирует весь tick.

Всё упирается в фазы цикла событий:
- timers — коллбеки от setTimeout и setInterval
- pending callbacks — I/O ошибки
- idle, prepare — внутренняя кухня libuv
- poll — новые I/O события
- check — очередь setImmediate
- close callbacks — закрытие соединений

Проблема: когда у вас 10 000 активных setTimeout, фаза timers отрабатывает десятки миллисекунд. Всё остальное стоит в очереди. I/O, новые запросы, ответы — всё ждёт, пока переберутся таймеры.

Реальный случай из практики
Был сервис с heartbeats для клиентов. Каждый клиент держал рекурсивный setTimeout:

function heartBeat(clientId) {
setTimeout(() => {
// Тяжёлая операция с БД + проверка состояния
heartBeat(clientId);
}, 1000);
}


Для 5000 клиентов каждый tick на фазе timers прогонял до 5000 коллбеков. Попутно лагали все остальные запросы — пользователи чувствовали задержки, мониторинг показывал event loop lag > 100ms.

Что с этим делать?
Во-первых, отлаживать. Берём профайлер Node.js:

node --prof app.js


Смотрим лог — находим, сколько времени уходит на фазу timers. Часто это открытие.

Во-вторых, оптимизировать.
- Ограничьте количество активных таймеров. Сгруппируйте несколько heartbeat-задач в один setInterval.
- Там, где возможна замена, используйте setImmediate. Он живёт на фазе check — не блокирует poll и timers.
- Мониторьте event loop lag через process.hrtime или модуль event-loop-stats. Если lag > 50ms — это звоночек.

Можно ещё раскидать тяжёлые таймерные задачи по worker_threads — чтобы они не тормозили главный поток.

Вывод:
Большое количество таймеров — тихий убийца производительности, который часто замечают слишком поздно, но своевременный профилинг и рефакторинг очередей могут снизить latency в разы.