
Как сломать Swift Concurrency
rabbitShadow 12 минут назад Как сломать Swift Concurrency Средний 6 мин 138 iOS * Swift * Программирование * FAQ Нужно выполнять асинхронные операции, поддерживать многозадачность в приложении? Async/await к вашим...
<5 — 2026'da uzaya kaç SpaceX Starship fırlatması ulaşacak?
Значимый прорыв формирует отрасль ИИ: rabbitShadow 12 минут назад Как сломать Swift Concurrency Средний 6 мин 138 iOS * Swift * Программирование * FAQ Нужно выполнять асинхронные операции, поддерживать многозадачность в приложении? Async/await к вашим услугам - просто и приятно. Кооперативный пул эффективно переключает потоки между задачами, а компилятор проверяет типы на потокобезопасность.
И даже можно подсоединять старые части кода, написанные ещё на GCD! Вот только приложение на проде почему-то начало виснуть…Ниже разберем конкретные примеры (со схемами), как не стоит смешивать async/await-код с DispatchQueue (то же справедливо и для других блокирующих примитивов). Источник проблемСистема не выдаёт каждой Task отдельный поток.
Технические детали
Задачи выполняются на кооперативном пуле потоков, а количество доступных потоков не превышает числа активных ядер процессора. Apple описывает это в докладе Swift concurrency: Behind the scenes (WWDC21, сессия 10254)Когда задача не может выполниться тут же, она приостанавливается без блокировок. await - это потенциальная точка приостановки: если приостановка действительно происходит, задача освобождает поток, и он идёт обратно в пул, а своё состояние задача сохраняет в куче как continuation.
Освободившийся поток тут же подхватывает другую задачу. Если же задача завершается сразу и приостановки нет, то поток не освобождается. Поэтому можно дёшево порождать тысячи задач, это всего лишь небольшие аллокации в куче, а не отдельные потоки.
А вот блокирующий вызов GCD или бесконечная задача (цикл) - это не точка приостановки, они захватывают поток и не возвращают его в пул. Чем больше таких задач, тем выше шанс опустошить пул. Каждый способ из тех, что ниже, по-своему приводит к этой ситуации.
Отраслевые последствия
Набить пул блокирующими задачамиСамый простой способ - занять каждый поток пула задачей, которая его заблокирует до конца своего выполнения. Пример с DispatchQueue. sync:// Размер пула 2.
Запускаем 2 блокирующие задачи, каждая на своей очереди. <2 { } // застряла в очереди, выполнится не скороЗадача внутри sync не приостанавливается. Поток из пула ждет, пока блок отработает на очереди.
Если сделать так одновременно на каждом потоке пула, его пропускная способность упадёт до нуля. Задачи не приостановлены, потоки заблокированыПул оживает после завершения блоков. Но пока они выполняются, не продвигается ничего из того, что живёт на нём: неизолированные async-функции, обычные акторы, TaskGroup (@MainActor и очереди GCD при этом продолжают работать - у главного актора собственный executor на главном потоке, а у GCD свой пул).
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





