Ответ
Actor решает проблему гонок данных (data races) при работе с изменяемым состоянием в параллельном коде.
Ключевые решаемые проблемы:
- Data Races: Гарантирует, что доступ к изолированному (isolated) состоянию актора происходит последовательно. В один момент времени только одна задача может исполнять код, работающий с его свойствами.
- Упрощение синхронизации: Избавляет разработчика от необходимости вручную использовать примитивы синхронизации (
DispatchQueue,NSLock, семафоры), которые подвержены ошибкам (deadlocks, priority inversion). - Безопасность на уровне компилятора: Компилятор Swift статически проверяет, что код вне актора не обращается к его изолированным свойствам напрямую, вынуждая использовать
awaitдля взаимодействия.
Принцип работы: Actor изолирует свои изменяемые свойства. Все его методы и свойства, помеченные как nonisolated, считаются безопасными для параллельного доступа. Для вызова изолированного метода извне требуется await, что указывает на потенциальную приостановку текущей задачи до возможности безопасного доступа.
Пример:
actor BankAccount {
private(set) var balance: Double = 0.0 // Изолированное состояние
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) -> Bool {
guard balance >= amount else { return false }
balance -= amount
return true
}
}
// Использование
Task {
let account = BankAccount()
await account.deposit(amount: 100) // Доступ сериализован
let success = await account.withdraw(amount: 50)
print("Withdrawal successful:", success)
}
Важно: Actor защищает от гонок данных, но не от всех проблем параллелизма (например, race conditions на логическом уровне или голодание).
Ответ 18+ 🔞
Да ты посмотри, какой умный дядя придумал — Actor, блядь! Сидит, значит, и думает: "Ну как же эти распиздяи-разработчики вечно всё ебут с этими потоками? То deadlock, то race condition, то ещё какая-нибудь хуйня вылезет, в рот меня чих-пых!"
И вот, сука, родилась идея. Actor — это такой тип, который говорит: "Ребят, всё моё барахло — моё. Хотите потрогать? Извольте в очередь встать, блядь, и ждать, пока я освобожусь". И компилятор, этот занудный пидорас, стоит над душой и орёт: "А ну нахуй отсюда! Нельзя просто так взять и вызвать метод! Ты куда лезешь? Там же изолированное состояние, ёпта! Ставь await и жди, как все нормальные люди!"
Смотри, вот тебе живой пример, чтобы не быть, как та собака Муму, которая нихуя не поняла, пока её в мешок не запихали:
actor BankAccount {
private(set) var balance: Double = 0.0 // Вот это — святое, блядь. Никто просто так не подойдёт.
func deposit(amount: Double) {
balance += amount // Тихо, спокойно, без всяких гонок, как в хорошем публичном доме.
}
func withdraw(amount: Double) -> Bool {
guard balance >= amount else { return false } // Проверил — и хуй тебе, а не деньги.
balance -= amount
return true
}
}
// А теперь попробуй без очереди сунуться
Task {
let account = BankAccount()
await account.deposit(amount: 100) // Сидишь, ждёшь, как лох у парадного. Пока актор не освободится — нихуя.
let success = await account.withdraw(amount: 50) // Опять ждёшь, блядь. Зато спокойно.
print("Withdrawal successful:", success)
}
И вся соль, сука, в том, что компилятор сам тебя по рукам бьёт. Попробуй вызвать account.balance без await — получишь пиздюлину на этапе компиляции. Красота, да и только! Раньше бы самому с DispatchQueue или с каким-нибудь NSLock ебаться, а тут — взял актора, и как будто хуй с горы: всё само катится.
Но, чувак, не обольщайся. Это не волшебная таблетка от всех болезней. Актор от гонок данных спасёт — да, от того, чтобы два потока в одну переменную не кончали одновременно. Но если у тебя логика кривая, и ты, например, сначала проверяешь баланс, а потом через пять минут его снимаешь — то тут уже race condition на уровне бизнес-логики, и актор тебя не спасёт. Ты просто последовательно, по одному, сделаешь две ебанутые операции. Так что головой думать всё равно надо, а не только на компилятор надеяться.
Короче, инструмент охуенный, но панацеей не является. Как говорится, можно и ломом гвозди забивать, но молотком — удобнее. Вот Actor — это такой современный, эргономичный молоток для параллельного кода. Бери, пользуйся, только по пальцам себе не ударь.