Добавить объявление

Не создавайте Actor без причины: как избежать архитектурной ошибки

С появлением Swift Concurrency многие разработчики стали добавлять actor везде, где видят асинхронность. Это как использовать танк для поездки в магазин за хлебом: мощно, но бессмысленно и создает больше проблем, чем решает.

Вот простой и эффективный чек-лист, который позволит определить, нужно использовать actor или нет:

У вас есть состояние, которое не является Sendable?


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

  • Пример не Sendable: класс с изменяемым (var) свойством, которое является ссылочным типом (например, другим не-Sendable классом) и не защищен блокировками.

  • Пример Sendable: структура (struct) только с let свойствами простых типов (Int, String) или других Sendable типов.

Если у вас либо нет состояния, либо оно уже потокобезопасно (Sendable). actor для его защиты избыточен.

Операции с этим состоянием должны быть атомарными?


Атомарность означает, что промежуточное состояние объекта никогда не будет видно извне. Либо операция выполнена полностью, либо не выполнена совсем.

  • Пример атомарной операции: списание суммы со счета и ее зачисление на другой счет в банковском приложении. Эти два действия должны быть одним неделимым целым.

  • Пример не атомарной операции: загрузка данных из сети и их последующее отображение. Это два независимых шага, между которыми система может быть в корректном состоянии.

Если ваши операции можно разбить на независимые шаги или они не требуют такой строгой изоляции, возможно, хватит обычной очереди (DispatchQueue) или async/await с корректным проектированием.

Эти операции не могут быть выполнены на уже существующем actor (например @MainActor)?


Часто проблема решается не созданием нового изолированного острова actor, а правильным использованием существующих.

  • Проверьте: может ли ваша логика быть изолирована к @MainActor, если она касается UI? Или может ее стоит вынести в @concurrent функцию (Swift 6.2+), чтобы просто запустить в параллельном пуле потоков?

  • Классическая ошибка: создавать отдельный actor только для того, чтобы выгрузить работу с основного потока. Для этого есть async let, Task.detached или аннотация @concurrent.

Вы не исчерпали возможности существующих механизмов изоляции. Новый actor добавит накладные расходы на переключение контекстов без реальной необходимости.

Вывод:


Actor - это специальный и достаточно ресурсоемкий механизм, созданный для решения конкретной проблемы: строгой изоляции разделяемого изменяемого состояния. Его не следует применять автоматически для любой фоновой работы.

Прежде чем его использовать, необходимо честно ответить на три ключевых вопроса: есть ли у вас состояние, не являющееся потокобезопасным (Sendable), требуют ли операции с ним атомарности и действительно ли эту работу невозможно выполнить в рамках уже существующего контекста изоляции. Только утвердительные ответы на все три пункта оправдывают введение actor. Во всех остальных сценариях стоит отдавать предпочтение более легким инструментам, таким как async/await, проектирование с Sendable типами, классические DispatchQueue или новая аннотация @concurrent.
23.12.2025 9 106