Обновить

flushSync в React – костыль или спасение?

Вчера впервые попробовал flushSyncб который подвезли в React еще в 18 версии.
Классное решение для определенных моментов! Выглядит так, будто React выдал нам костыль, но сразу предупредил: пользоваться с осторожностью.

❓ Почему это вообще нужно? (Для тех, кто не совсем в теме)
В React изменения в useState или в useEffect выглядят синхронными, но на самом деле они асинхронны.

Простой пример:

...

const [count, setCount] = useState(0);

console.log(count); // 0

setCount(1); console.log(count); // Всё ещё 0! 😲

...

Кажется, что setCount(1) сразу меняет count, но на самом деле новое значение попадёт в консоль только при следующем ререндере.

То же самое в useEffect:

...

useEffect(() => { console.log("Эффект сработал!"); }, [count]);

setCount(1); console.log("А это после setCount");

...

Лог "А это после setCount" появится в консоли раньше, чем "Эффект сработал!", потому что useEffect выполняется уже после рендера.

Как flushSync меняет поведение?

Обычно React группирует обновления (batching) и откладывает ререндер до конца текущего цикла. flushSync ломает это поведение и заставляет React сразу выполнить ререндер.

function Example() { 
    const [count, setCount] = React.useState(0); 
    const ref = React.useRef(null);
    const handleClick = () => { 
        flushSync(() => setCount(count + 1)); 
        console.log("Высота элемента:", 
            ref.current?.offsetHeight); 
        };

    return (<button onClick={handleClick}>
        Добавить  {count}
    </button>); 
} 

Что тут происходит?
Без flushSync React подождал бы до конца текущего вызова и только потом обновил DOM.
С flushSync обновление происходит немедленно, и console.log видит уже новый DOM.

React нас предупреждает
В документации прямо сказано:

"flushSync – это низкоуровневый API. Используйте его только тогда, когда вам действительно нужно измерить DOM сразу после обновления состояния."

Когда не стоит использовать flushSync?
Если можно обойтись обычными useEffect или useLayoutEffect.
Если batching работает нормально и не мешает.
Если нет необходимости немедленного ререндера (иначе можно уронить производительность).

Итог
flushSync – мощный инструмент, но использовать его нужно осознанно. Он нужен в случаях, когда важно немедленно обновить стейт и тут же прочитать DOM (например, для анимаций).

Если понравился пост присоединяйтесь к моему каналу в Telegram по ссылке https://t.me/+qbK9ZPuAocI2MWUy.
Там я делюсь своим опытом и пишу материалы которые будут полезны как новичкам, так и матерым разработчикам.

Теги:
Рейтинг0
Комментарии0

Как мы запустили Qwen3.8–27B целиком на RTX 5060 8 GB и получили ~30 токенов/с

Наш проект называется ExVRAM Lab. Это открытая исследовательская лаборатория, в которой мы проверяем, насколько большие локальные LLM можно запускать на обычных видеокартах с ограниченным объёмом VRAM, если использовать ultra‑low‑bit quantization, полное размещение весов на GPU и существующие open‑source inference‑технологии.

ExVRAM расшифровывается как Exchange Compute for VRAM. Основная идея проекта — в ряде сценариев выгоднее потратить часть свободной вычислительной мощности GPU на работу с более компактным представлением весов, чем хранить часть модели в оперативной памяти и постоянно передавать данные через PCIe.

Когда мы начинали проект, исходный вопрос был достаточно простой: можно ли запустить dense‑модель примерно на 27 миллиардов параметров на видеокарте всего с 8 ГБ VRAM так, чтобы она не просто «запустилась», а работала полностью на GPU, поддерживала длинный контекст и обеспечивала нормальную интерактивную скорость генерации.

В качестве основной тестовой системы мы используем NVIDIA GeForce RTX 5060 8 GB на архитектуре Blackwell. Основная модель в текущих экспериментах — Qwen3.8–27B.

Сначала результат выглядел не слишком впечатляюще. Модель запускалась, но значительная часть весов оставалась в системной памяти. Около 5,7 GiB весов находилось на GPU, ещё примерно 2,5 GiB — на CPU. Скорость генерации составляла порядка 3,8–5,5 токена в секунду.

При этом сама видеокарта была загружена далеко не полностью.

Это стало одним из первых важных наблюдений проекта. Проблема заключалась не столько в нехватке вычислительной мощности RTX 5060, сколько в том, что часть decoder weights находилась в RAM. Во время autoregressive generation данные приходилось постоянно передавать между CPU и GPU через PCIe.

Как мы запустили Qwen3.8–27B целиком на RTX 5060 8 GB и получили ~30 токенов/с

Публикации