Ответ
Да, могут, но это приводит к состоянию гонки (race condition) и неопределенному поведению, если доступ не синхронизирован. Параллельная запись может повредить данные.
Пример проблемы (гонка данных):
var counter = 0
DispatchQueue.concurrentPerform(iterations: 100) { _ in
counter += 1 // Небезопасно: несколько потоков читают и пишут одновременно
}
print(counter) // Результат может быть меньше 100
Решение — использование механизмов синхронизации:
DispatchQueueс барьером (barrier) или синхронным доступом (sync) для сериализации операций записи.NSLock/os_unfair_lockдля явной блокировки.@MainActorдля безопасного обновления UI из разных потоков.Actor(Swift 5.5+) — современный тип, обеспечивающий изоляцию.
Пример с Actor:
actor SafeCounter {
private var value = 0
func increment() { value += 1 }
func getValue() -> Int { value }
}
// Использование:
let counter = SafeCounter()
Task {
await counter.increment() // Доступ изолирован, гонок нет
} Ответ 18+ 🔞
А, слушай, тут один умник спрашивает, можно ли в Swift писать в одну переменную из нескольких потоков. Ну, внатуре, можно, конечно, блядь! Только потом не удивляйся, что у тебя данные похожи на фарш после мясорубки, которую держали десять пьяных слесарей.
Это, блядь, классическая гонка, race condition называется. Состояние такое, ёпта, неопределённое — сегодня отработало, завтра словил креш, послезавтра значение как из жопы левой ноги вылезло. Полный пиздец, короче.
Смотри, вот тебе наглядный пиздец в коде:
var counter = 0
DispatchQueue.concurrentPerform(iterations: 100) { _ in
counter += 1 // А вот тут-то и начинается цирк, блядь! Все лезут разом!
}
print(counter) // И получишь ты не 100, а какую-нибудь хуйню вроде 87 или 93. Удивление пиздец!
Видишь? Все потоки как мартышлюшки на банан кинулись — читают значение, каждый своё дерьмо прибавляет и обратно пишет. Итог — волнение ебать, а доверия к результату — ноль ебать.
Так что делать-то, спрашиваешь? Ну, вариантов, блядь, овердохуища, как синхронизировать этот бардак.
Можно старым добрым способом, через DispatchQueue с барьером или просто синхронно всё делать, чтобы очередь была. Можно замками (NSLock) махаться, как в старые добрые, чтоб только один в этот момент в сортир заходил.
Для UI-обновлений, там, @MainActor — святое дело, чтоб не вышло, что интерфейс рвётся из всех щелей одновременно.
Но самый, блядь, модный и правильный способ сейчас — это Actor. Свифт 5.5 его впендюрил, и слава богу. Это такой тип, который сам за собой следит, чтобы к его внутренностям только один поток в один момент времени лапал. Красота!
Вот, смотри, как красивше:
actor SafeCounter {
private var value = 0
func increment() { value += 1 }
func getValue() -> Int { value }
}
// Использование:
let counter = SafeCounter()
Task {
await counter.increment() // Всё, блядь, изолированно. Никаких гонок, никакого хаоса. Тишина и покой.
}
Вот и вся магия. Хочешь без головной боли — используй акторы. Не хочешь — ну, страдай потом, дебажь эти ебушки-воробушки с гонками, чих-пых тебя в сраку. Выбор за тобой.