Post #712
352
🚧 Ваш
Вы пишете многопоточный код. У вас есть общий ресурс (например, in-memory кэш сессий). Вы знаете, что
Вы берете
Поздравляю, вы сделали лучше. Но под большим contention (высокой конкуренцией) ваш код всё равно будет страдать.
В чем проблема Mutex?
Да, он не блокирует поток. Но
Когда 100 корутин ломятся в один лок, 1 получает доступ, а 99 - саспендятся. Саспенд - это не бесплатно. Это сохранение стейт-машины, аллокации
🛠 Как от этого уходят Сеньоры? (2 пути)
Путь 1: Lock-free (Для простых стейтов)
Если у вас счетчик или простая ссылка на объект, забудьте про локи. Используйте атомики (CAS-операции — Compare-And-Swap). Они выполняются на уровне железа процессора.
Путь 2: Thread Confinement (Для сложной логики)
Если логика внутри лока большая (нужно сходить в мапу, проверить список, обновить 3 переменные) - CAS не спасет.
Вместо того чтобы обносить данные забором из локов, спрячьте данные в один поток.
Вспоминаем наш прошлый пост про
Почему Confinement (ограничение потока) лучше?
1. Вы избавляетесь от Deadlocks по определению.
2. Процессору гораздо проще прогнать очередь инструкций на одном ядре (работает L1/L2 кэш процессора), чем прыгать между потоками, пытающимися захватить
3. Код становится линейным и предсказуемым.
Вывод:
Если ресурс "горячий" (в него долбятся постоянно) - изолируйте стейт в
Признавайтесь, у кого проект усыпан
📲 Мы в MAX
✍️ @kotlin_lib
Mutex тормозит корутины. Как перестать лочить и начать житьВы пишете многопоточный код. У вас есть общий ресурс (например, in-memory кэш сессий). Вы знаете, что
synchronized в корутинах - это зло (блокирует системный поток).Вы берете
Mutex и оборачиваете код в mutex.withLock { ... }.Поздравляю, вы сделали лучше. Но под большим contention (высокой конкуренцией) ваш код всё равно будет страдать.
В чем проблема Mutex?
Да, он не блокирует поток. Но
withLock - это suspend функция.Когда 100 корутин ломятся в один лок, 1 получает доступ, а 99 - саспендятся. Саспенд - это не бесплатно. Это сохранение стейт-машины, аллокации
Continuation, а потом дорогой диспетчеризированный возврат (resume) каждой корутины к жизни.🛠 Как от этого уходят Сеньоры? (2 пути)
Путь 1: Lock-free (Для простых стейтов)
Если у вас счетчик или простая ссылка на объект, забудьте про локи. Используйте атомики (CAS-операции — Compare-And-Swap). Они выполняются на уровне железа процессора.
// ❌ Медленно:
val mutex = Mutex()
var count = 0
// ... mutex.withLock { count++ }
// ✅ Летает:
val count = AtomicInteger(0)
// ... count.incrementAndGet()
// 🧠 Для Kotlin-объектов:
val state = MutableStateFlow(InitialState)
// Под капотом использует CAS-цикл без локов!
state.update { it.copy(...) }
Путь 2: Thread Confinement (Для сложной логики)
Если логика внутри лока большая (нужно сходить в мапу, проверить список, обновить 3 переменные) - CAS не спасет.
Вместо того чтобы обносить данные забором из локов, спрячьте данные в один поток.
Вспоминаем наш прошлый пост про
limitedParallelism(1) - это официально рекомендуемая JetBrains замена устаревшим Actors.
class SessionManager {
// Создаем свой "однопоточный" диспетчер
private val stateContext = Dispatchers.Default.limitedParallelism(1)
// Переменная вообще без потокобезопасных оберток!
private val cache = mutableMapOf<String, Session>()
suspend fun updateSession(id: String, data: Session) {
// Все операции с кэшем встают в аккуратную очередь
// на выполнение в один поток. Никаких race conditions.
withContext(stateContext) {
val existing = cache[id]
cache[id] = merge(existing, data)
}
}
}
Почему Confinement (ограничение потока) лучше?
1. Вы избавляетесь от Deadlocks по определению.
2. Процессору гораздо проще прогнать очередь инструкций на одном ядре (работает L1/L2 кэш процессора), чем прыгать между потоками, пытающимися захватить
Mutex.3. Код становится линейным и предсказуемым.
Вывод:
Mutex хорош, когда коллизии редки.Если ресурс "горячий" (в него долбятся постоянно) - изолируйте стейт в
StateFlow (если можно) или в отдельный limitedParallelism(1) контекст (если логика сложная).Признавайтесь, у кого проект усыпан
Mutex() на каждом чихе? 👇📲 Мы в MAX
✍️ @kotlin_lib
- 🔥 6
- 👍 3











