惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
腾讯CDC
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
B
Blog
S
SegmentFault 最新的问题
P
Privacy & Cybersecurity Law Blog
T
Threatpost
博客园 - 聂微东
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
C
Check Point Blog
N
Netflix TechBlog - Medium
D
DataBreaches.Net
爱范儿
爱范儿
IT之家
IT之家
S
Secure Thoughts
M
MIT News - Artificial intelligence
NISL@THU
NISL@THU
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
有赞技术团队
有赞技术团队
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
Schneier on Security
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
雷峰网
雷峰网
Project Zero
Project Zero
博客园 - Franky
H
Heimdal Security Blog
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Меня раздражает, как объясняют асинхронность
TeaDove · 2026-05-12 · via Все публикации подряд на Хабре

Если что такое параллелизм более-менее все разработчики понимают, то объяснение асинхронности через аналогии с кассирами/поварами не ложно, но, как мне кажется, вредно, так как вводит в очень большое заблуждение.
В данной статье я разберу эту проблему на примерах Python и Go и попробую дать свою правильную аналогию.

TL;DR

Асинхронность и многопоточка решают одну и ту же задачу для IO-bound операций - конкурентность, - но отличаются только синтаксисом, экосистемой и производительностью.

Для IO-bound!

Для CPU-bound кода выгоды в асинхронности нет, параллелизм достигается на потоках.

Вопрос?

Как-то раз в интернете я наткнулся на опросник, который используют HR при первом контакте с кандидатом на позицию гофера.

Скрытый текст

Очень надеюсь, что этот опросник - фейк и его никто никогда не использовал

Один из вопросов в нем звучал так:

"Если к функциям дописать ключевое слово go, они будут работать асинхронно?"

Для не гоферов

Ключевое слово go вызывает функцию в отдельной горутине, очень грубо говоря, как питоновское asyncio.create_task

Странная формулировка, подумал я, но чисто технически ответ же - "да"? Может вопрос с подвохом и горутину надо заджойнить (добавить sync.WaitGroup)?
Или вопрос про GOMAXPROCS? Если разрешить использовать только 1 OS поток, то горутина, конечно, будет работать асинхронно, но если 2 - может и параллельно.
Или вопрос про то, что будет с горутинами, что еще не завершили работу, но основная горутина (main) завершилась?

Оказывается, ответ таков:

"во-первых нет, в Go нет асинхронности, во-вторых нужна синхронизация"

Отвратительность этого ответа (и вопроса) я даже не хочу обсуждать, но давайте остановимся на асинхронности. Разве ее нет в Go? Да вроде есть, если определять ее как "переключение между лёгкими задачами без блокировки OS потоков", то в Go, конечно, она есть. Иначе как у нас могла бы быть конкурентность при GOMAXPROCS=1? На OS потоках с блокировками что ли, хахаха?

Скорее всего авторы имели в виду синтаксис JS/Python с async/await/promise, его и правда в Go нет, но причем тут синхронизация и почему кандидат должен её упомянуть - я так и не понял :)

Объяснение?

Если вы попробуете загуглить, что такое асинхронность и чем она отличается от мультипоточности, то слоп-машина гугла ответит вам так:

Ответ AI Overview гугла на "асинхронность и многопоточность"

Ответ AI Overview гугла на "асинхронность и многопоточность"

Звучит, вроде, корректно, но что-то тут не так. Прямой лжи тут нет.
А потом нам дается аналогия:

Аналогия от AI Overview

Аналогия от AI Overview

Вроде тоже все правильно, но....
Точно!

По этим аналогиям может сложиться впечатление, будто в многопоточности, если вы варите суп, то должны сначала его полностью доварить и не можете переключиться на другую задачу. Да и необходимость синхронизации корутин никто не отменял.
А я напомню, что в доисторические времена (25 лет назад) частенько встречались ЭВМ всего лишь с 1 ядром, при этом про корутины/горутины никто и не слышал. Как же тогда работал код, как машина не сгорала, если одновременно открывалась ICQ, Warcraft 3, Skype и IE?

Скрытый текст

Старые слабенькие компьютеры, конечно, не потянули бы сразу все приложения, но какая-то многозадачность-то все равно же была!

Да через те же самые потоки! Кто вообще сказал, что потоки могут параллелить только CPU-bound? Кто сказал, что нельзя запустить 100 потоков на 1 ядре и переключать IO-bound задачи, "вы ставите чайник на плиту, ..., не блокируетесь и начинаете резать овощи".
Вы можете зайти в top/Activity Monitor/диспетчер задач и посмотреть, сколько какой процесс насоздавал потоков.
Например, на моем 8-ядерном маке у одного процесса вообще 524 потока :)

Мой Activity Monitor

Мой Activity Monitor

При этом так объясняются различия почти всегда и везде!
Тианголо в документации к FastAPI также объясняет asyncio, только через бургеры, а не супы.

Скриншот из статьи про asycnio

Скриншот из статьи про asycnio

Где-то в интернетах есть еще такая картинка:

Опять же, она не противоречит реальности, внутри одного потока и правда в моменте может выполняться только 1 задача, корутины же позволяют переключаться между задачами внутри одного потока.
Но визуализация, почему-то, игнорирует тот факт, что OS самостоятельно переключает потоки, при этом OS также следит за блокировками (IO-bound операциями) и также паркует потоки.

Более корректной можно было бы визуализировать многопоточку так:

Исправленная версия

Исправленная версия

Потоки могут работать как в параллель, OS может кидать их с ядра процессора на ядро, при этом они могут и переключаться!

А как в реальности?

Термины

Процесс

Это сущность на уровне OS, имеет свою область памяти, в которую не могут ходить другие процессы и, собственно, код, который выполняется в процессе. Каждый процесс имеет минимум 1 поток на котором и работает код.

Дополнение

Конечно, процессы имеют и больше свойств: разрешения, файловые дескрипторы, идентификатор и тд, но в данной статье это не так важно.

Поток/тред

Это просто последовательность инструкций, которые нужно выполнить процессору. Если поток работает слишком долго или натыкается на IO-bound операцию, то OS может его остановить, выгрузить и запустить другой поток.

Корутина

Сущность на уровне языка программирования. Архитектура, реализация и наименование дрейфуют от языка к языку. Например, в Go это горутины, в Джаве - виртуальные треды и тд и тп. Но логика почти всегда одна и та же - корутины это те же самые потоки, но легковесные. Иногда корутинами называют останавливаемыми функциями (в Python), которые планировщик/event loop паркует и запускает, по сути как те же потоки.

Параллелизм

Свойство программы выполнять код одновременно. Не переключаться между задачами, а именно одновременно работать. Параллелизм достигается за счет многоядерности процессора и потоков: чтобы запустить N задач параллельно надо иметь хотя бы N-ядерный процессор и N потоков.

Асинхронность

Метод выполнения задач, при котором IO bound операции не блокируют основной поток. Иными словами в современном мире это просто выполнение задач в корутинах/горутинах/виртуальных потоках.

Конкурентность

Самый непонятный, как мне кажется, термин. По сути это свойство программы выполнять задачи с переключениями, при этом не обязательно через корутины/горутины. Получается, что код на Python будет конкурентным как на корутинах, так и на потоках.

Конкретнее

Разберем на питоне.
Реальность такова, что корутины выполняют ту же функцию, что и OS потоки - конкурентное выполнение кода. Иными словами, через них можно запустить 2 задачи и переключаться между ними.

GIL

В Python из-за GIL параллельности, конечно, не получится достичь на потоках или корутинах, но вот переключение есть в обоих решениях. В Python 3.14 GIL можно отключить, но это уже совсем другая история.

Но в чем же отличие корутин от OS потоков? Зачем их использовать, если и то, и то дает один и тот же результат?
Корутины весят мало - 1-5 KB ОЗУ.

Так мало?

Имеется в виду сам объект корутины именно в Python. Со стеком, задачей, контекстом и всем остальным она, конечно, будет больше, но все равно намного меньше потока, который занимает мегабайты.

Переключение контекста (то есть остановка выполнения одной корутины на ядре и запуск другой на том же ядре) в корутинах быстрее - так как корутины управляются рантаймом языка, а не OS, переключение происходит в User Space, а не Kernel Space, что, банально, требует меньше операций.

Очень важно: сам факт того, что корутина не блокирует поток, в котором она выполняется, нам важен только потому, что мы не хотим лишних переключений контекстов, потому что любая блокировка может вызвать переключение в Kernel Space. При этом сами корутины, так же как и OS потоки, умеют блокироваться и переключаться :)

Интересный нюанс - то, что было описано выше, релевантно и для других языков программирования. Горутины в Go также весят мало (2-4 KB), переключаются быстро и также используют kqueue/epoll для неблокирующих обращений к OS. Отличий, конечно, тоже много, например, горутины умеют и в параллелизм.

Нюанс

В Go в принципе нет доступа к управлению OS потоками, по сути разработчик может создавать только горутины, а они умеют как в параллельность, так и в асинхронность.

Важно внести небольшую архитектурную ясность: любой процесс всегда запускает хотя бы один поток. При этом параллелизм, то есть единомоментное выполнение кода на N ядрах, возможен только при создании нескольких потоков. Поэтому, например, если вы в Go запустите 10 CPU-bound функций в 10 горутинах в системе с 10 ядрами CPU, то у вас будет задействовано 10 OS потоков и эти 10 горутин будут работать на своих потоках.

Уточнение

Теоретически, конечно, может создаться больше потоков, например, при syscall, CGO-вызовах и тд.

Если вернуться к Python, то я хочу позволить себе очень громкий тезис:

Асинхронность и мультипоточка в Python решают одну и ту же задачу, но отличаются только синтаксисом, экосистемой и производительностью.

Что?
Предположим, вы пишете бекенд на FastAPI (веб-фреймворк) и ходите в Redis через redis-py и Postgres через psycopg3. Все 3 библиотеки, что я описал, умеют как в asyncio, так и в многопоточку. Вы можете написать функционально идентичный код, при этом синтаксически вам нужно будет лишь в нескольких местах поменять конфиги и проставить async и await в нужных местах. Флоу самого кода же будет идентичным.

# На потоках
@app.post("/save")
def save(kv: KV) -> None:	
  redis_client.set(kv.key, kv.value)	
  
# На корутинах
@app.post("/asave")
async def asave(kv: KV) -> None:	
  await redis_aclient.set(kv.key, kv.value)

Обе функции save и asave конкурентны: если 10 пользователей отправят единомоментно 10 запросов POST /save, FastAPI возьмёт 10 OS потоков и обработает запросы. Аналогично с POST /asave, только FastAPI запустит 10 Python корутин.

Внимательный читатель

Внимательный читатель, конечно, может предъявить, что, например, в asyncio есть cancel, а в threading - нет, а еще исключения автоматически в asyncio не пробрасываются. Но это как раз синтаксическое отличие asyncio от threading.

Также можно сказать, что asyncio красит функции, из sync функции просто не вызовещь async функцию, а sync функцию может заблокировать поток, если её неправильно вызывать из asynс. Но это и есть экосистемность.

А в других языках?

Как я уже сказал выше, в Go в принципе нет доступа к OS потокам, при этом в других языках, типа C#, Java, Kotlin, данный тезис на удивление верен (частично). Каких-то выгод, кроме производительности, корутины дают редко.

Аналогия

Давайте попробуем придумать более корректную аналогию.

Одноядерный процессор

Представьте: есть ресторан, в котором работает один сотрудник (это у нас аналог ядра процессора), при этом он немного глупенький сотрудник, который сам не умеет переключаться между задачами (потоками).
Вы заказываете борщ, а он:

  • Берет заказ

  • Ставит бульон на готовку

  • Ждет приготовления бульона: пока тот готовится - просто смотрит

  • Снимает бульон

  • Нарезает овощи

  • Нарезает хлеб

  • Подает еду

Иными словами - делает все последовательно, без переключений и очень неэффективно!

Одноядерный процессор с OS

Добавим ему менеджера.
Теперь у него есть начальник (планировщик OS), который постоянно висит у него над душой и раз в минуту может заставить его делать другую задачу:
"Поставил готовить бульон и больше делать нечего (заблокировался)? Сходи подмети пол!"
Уже лучше. Это обычный мультитрединг на одном ядре.

Пояснение про время

Только в Linux планировщик переключает потоки, конечно, чаще, чем раз в минуту. Значения могут разниться в зависимости от настроек, версий и тд и тп, но будет порядка ~5 мс. То есть имея 10 потоков на одном ядре, каждый из которых выполняет CPU-bound операции, переключение будет происходить каждые 5 мс. Опять же, это число - не константа и есть шедулеры, что выставляют его динамически, например, исходя из приоритетов.

Многоядерный процессор с OS

А теперь нанимаем много сотрудников (многоядерный процессор), и пусть менеджер также следит за всеми: кто-то пошел еду разнести, кто-то бульон варит, кто-то убирается.
Но наш менеджер тоже немного глупый, он не знает, что дорого официантов постоянно переключать на задачи поваров, потому что тогда им приходится менять одежду, мыть руки, а вспоминать как и что готовить - медленно!

Многоядерный процессор с OS и корутинами

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

  • Принять заказ

  • Сделать заготовки

  • Приготовить бульон

  • Нарезать хлеб

  • И тд и тп

Пусть официанты теперь разносят еду, принимают заказы и взимают плату, а повара - только готовят. При этом в готовке они сами переключаются между задачами, отдельный менеджер им не нужен! (асинхронность)
Таким образом, мы сняли загрузку с менеджера (OS), ускорили переключение между задачами (корутинами) и уменьшили когнитивную загрузку работников (RAM) - им больше не нужно думать вообще про весь ресторан, только про свою зону ответственности.

Конечно, у этой аналогии есть свои изъяны, но она хотя бы показывает разницу между потоками и корутинами - и то и то работает хорошо, утилизирует все доступные ресурсы, позволяет одному исполнителю (ядру) выполнять несколько задач, переключаясь между ними, но корутины просто экономнее.

Почему?

Почему же наши коллеги так часто объясняют асинхронность как-то неправильно?

По опыту прохождения собесов и обсуждений с коллегами, мне кажется, что причина кроется в количестве терминов. Корутины в разных языках работают по-разному, где-то вообще вместо них горутины, а где-то виртуальные потоки, которые вроде те же самые лайттреды, но другие! Да еще и слово "конкурентность" какое-то непонятное, вроде часто используется для описания асинхронности, но, как мы выяснили, конкурентность можно реализовать и на потоках и даже на процессах (этого, конечно, делать не надо).

Спасибо за внимание, всех зову поспорить в комменты :)

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

100%Да! (автор зря придрался)1

0%Нет!0

Проголосовал 1 пользователь. Воздержался 1 пользователь.