Как Actor в Swift обеспечивает потокобезопасность в async/await?

«Как Actor в Swift обеспечивает потокобезопасность в async/await?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Actor обеспечивает потокобезопасность через изоляцию состояния и сериализацию доступа. Каждый actor имеет внутреннюю очередь (mailbox), и доступ к его изменяемому состоянию возможен только через асинхронные вызовы (await). Компилятор гарантирует, что в один момент времени выполняется только одна задача, изменяющая состояние actor, предотвращая race conditions.

Пример actor:

actor Counter {
    private var value = 0

    func increment() {
        value += 1
    }

    func getValue() -> Int {
        return value
    }
}

// Использование
let counter = Counter()
Task {
    await counter.increment()
    print(await counter.getValue()) // Гарантированно 1
}

Ключевые механизмы:

  1. Изоляция: Свойства и методы actor изолированы по умолчанию.
  2. Сериализация: Вызовы методов, изменяющих состояние, ставятся в очередь.
  3. await обязателен: Любой доступ к actor извне требует await, что явно указывает на потенциальную приостановку.
  4. Не блокирующий: В отличие от locks, actor использует кооперативную модель async/await, что эффективнее для конкурентности.