Concurrency, Synchronization and Consistency. Пост № 20. Масштабируемость Read-Write блокировки. False Sharing.
В прошлом посте мы с вами разобрались с основными моментами RW примитивов. Как и обещал - переходим к практике. У RW блокировок в классической реализации есть одна проблема из-за которой производительность операций чтения не будет расти линейно с ростом количества потоков.
Почему? Давайте вспомним самое начало цикла постов где мы обсуждали кеши CPU. В современном компьютере много ядер, работающих независимо и обеспечивающих параллелизм. Но когда они работают над общими данными они синхронизируются друг с другом обеспечивая когерентность кешей. Нужно это для того чтобы писать согласованные программы.
Причем здесь RW Mutex? Если вы внимательно изучали прошлый пост то увидели что я упомянул важную деталь - этот тип мьютекса ведет учет читателей. Именно эти данные и нужно каждый раз синхронизировать ядрам между собой чтобы программа вела себя корректно.
Это false sharing - ситуация, когда несколько потоков одновременно обращаются к переменным, которые находятся в одной кеш-линии. Кеш-линия - это минимальная единица данных, которая копируется из оперативной памяти в кеш процессора.
Что происходит на практике. Пошаговый алгоритм.
Представим что у нас N ядер и N потоков.
- В кеше каждого процессора есть данные нашего мьютекса.
- Ядро Х дает потоку доступ на чтение, увеличивает количество читателей на 1.
- Все остальные ядра по протоколу когерентности получают уведомления о том что данные изменены и их нужно перечитать. В собственном кеше каждое ядро помечает данные "грязными".
- Ядро при попытке поработать с мьютексом получает cache miss, и идет читать данные из основной памяти. Чтение из L1 кеша - 0.5ns а из основной памяти - 100ns.
Следствие - наша программа вместо полезной работы будет заниматься пинг-понгом и синхронизацией кешей. Чем больше ядер у машины, тем более явно это будет проявляться.
Выводы
Read Write блокировки только на первый взгляд кажутся очевидным выбором при написании highload программ. Обязательно экспериментируйте с ними и пробуйте сначала воспользоваться стандартным мьютексом, может оказаться что он будет работать лучше.
В следующем посте на примерах кода попробуем вывести определенные закономерности и лайфхаки когда использовать RWMutex а когда обычный. А еще дальше расскажу о том какие трюки применяют умельцы работающие в супер нагруженных продуктах чтобы выжимать максимум из железа.
-----
Если вам понравился пост, поддержите его реакциями и комментариями. Мне важно увидеть вашу обратную связь. Спасибо!
📖 Оглавление
Post #433
1.53K
- 👍 20
- 🔥 14