и посмотреть медиа
Евгений Козлов - IT и backend
и посмотреть медиа
IT-канал от опытного разработчика: backend, Data, System Design, concurrency, algorithms, infrastructure, reliability и карьера.
IT-канал от опытного разработчика: backend, Data, System Design, concurrency, algorithms, infrastructure, reliability и карьера.
bot de IA para clonar texto a voz y voz en Telegram. Cree audio utilizando la red neuronal de forma rápida y fácil.
💻 Канал Евгения Козлова посвящен глубоким аспектам IT-разработки. Автор делится знаниями, накопленными за 14 лет написания кода и 10 лет в production. Руководитель команды инженеров рассказывает о backend, Data и System Design.
🚀 Особое внимание уделяется concurrency, performance и algorithms. Разбираются infrastructure и reliability систем. Полезно для разработчиков, желающих углубить экспертизу и понять, как строить надежные масштабируемые решения.
📈 Темы карьеры и менеджмента помогают расти профессионально. Реальные кейсы из практики делают контент ценным для инженеров всех уровней.
Concurrency and Consistency. Non-blocking, lock-free and async. Пост №4. Гарантия отсутствия блокировок. В прошлом посте рассмотрели классический пример - конкурентная работа со счетами пользователей. Код довольно простой и наглядный, и даже соответствует гарантии которую разбирали. Но с ним есть проблема - он неправильный. - Мы буквально можем потерять операцию и как следствие деньги. - У нас возможен дедлок, если в один и тот же момент два пользователя переведут друг другу денежку. Как чинить эти проблемы? Шаг №1 - Заменить атомики на мьютексы. Шаг №2 - Добавить упорядочивание в захват мьютексов. package main import ( "sync" "unsafe" ) type SafeAccount struct { mu sync.Mutex balance int64 } func transferSafe(from, to *SafeAccount, amount int64) { first, second := from, to if uintptr(unsafe.Pointer(from)) > uintptr(unsafe.Pointer(to)) { first, second = to, from } first.mu.Lock() second.mu.Lock() from.balance -= amount to.balance += amount second.mu.Unlock() first.mu.Unlock() } Возвращая мьютексы мы теряем любые намеки на неблокирющую синхронизацию, зато код корректный и предсказуемый. Опять трейдоффы, что ж с ними поделаешь. Но раз перед нами стоит цель - научиться писать программы в неблокирующем стиле нужно продолжать погружение. Для начала определение: Гарантия отсутствия блокировок (Lock-free) - наш код гарантирует что в случае конкурентного исполнения кто-то обязательно достигнет прогресса. Вспомним наш "неправильный" пример про операцию transfer. Несмотря на неправильность, тем не менее он отлично демонстрирует гарантию obstruction-free. А что насчет lock-free? Гарантируется ли что при конкурентном запуске кто-то из участников обязательно достигнет прогресса? Такая гарантия отсутствует. Код допускает ситуацию livelock - потоки что-то делают, но постоянно откатываются назад, потому что конкурент успевает изменить общее состояние и нужно перечитывать заново, чтобы ничего не потерять. Получается что и не lock-free + критичные баги. Причина у двух следствий одна - в нашем алгоритме больше одного атомика. И вдобавок между ними есть связь, они части одного целого. Разделяя наше состояние на 2 части у нас не остается механизма для того чтобы работать с этими частями атомарно вместе, только по отдельности. Классические структуры данных, например стеки или очереди если нужна lock-free гарантия всегда реализуются через один атомик или несколько, при этом абсолютно независимых между собой. При таком дизайне гарантируется что какой бы ни была конкуренция - один участник точно достигнет успеха. Что такое Lock-free стек можно посмотреть здесь вместе с сопутствующей ABA Problem. Фух, многовато текста получилось, поэтому уже в следующем посте мы вернемся к функции transfer и сделаем её lock-free. Спойлер: будет сурово, поэтому готовимся морально и физически😁
Открыть канал и посмотреть медиаConcurrency and Consistency. Non-blocking, lock-free and async. Пост №4. Obstruction-free или Гарантия отсутствия препятствий. В прошлом посте мы дали все необходимые определения и провели параллели. Но все таки мы с вами теоретики, а не практики, поэтому без кода обойтись не могло. Гарантию obstruction-free легче всего начать объяснять на примере кода, который мы все хотя бы раз в жизни писали - thread-safe структура данных закрытая мьютексом, например мой любимый счетчик: std::mutex m; int shared_value = 0; void increment() { m.lock(); // (*) shared_value++; // долгая критическая секция m.lock(); } Потоков N, где N > 1. Соответствует ли код obstruction-free? Нет, не соответствует. Вспоминаем как у нас работает ОС. У нас есть планировщик который может остановить выполнение программы в любой момент, чтобы дать ресурс кому то еще. И теперь ситуация: - Поток №1 захватывает мьютекс и его сразу же усыпляет ОС чтобы разбудить поток №2 - Поток №2 проснулся, пытается тоже сделать increment, но терпит неудачу, так как сосед уже захватил мьютекс. - Поток №2 после нескольких попыток засыпает потерпев неудачу. Видим, что нет ни малейшего намека на выполнение требований из определения термина. В программе нет конкуренции, один поток работает, но достигнуть прогресса не может, так как ресурс захвачен соседом. Поэтому делаем вывод - код работающий в блокирующем режиме синхронизации не соответствует гарантии obstrcution-free. ——— Еще ситуация, "работаем в криптовалюте" переводим виртуальные денежки между счетами, естественно с гарантиями отсутствия потерь и дублирования: struct Account { std::atomic version; int balance; }; void transfer(Account& from, Account& to, int amount) { while (true) { int v1 = from.version.load(); int v2 = to.version.load(); int newFromBalance = from.balance - amount; int newToBalance = to.balance + amount; if (from.version.compare_exchange_strong(v1, v1 + 1)) { if (to.version.compare_exchange_strong(v2, v2 + 1)) { from.balance = newFromBalance; to.balance = newToBalance; return; // успех } from.version.store(v1); } } } Здесь ситуация отличается значительно. Если у нас несколько потоков, но работает только один - мы всегда будем достигать прогресса, так как у нас нет конкурентов за значения атомарных переменных. CAS операции всегда будут успешны и больше одной итерации в цикле нам не грозит. Такой код соответствует гарантии obstruction-free. Но обольщаться рано, не зря в быту обычно все упоминают lock-free а не obstruction-free ведь её недостаточно чтобы писать высокопроизводительные программы. В следующих постах разберемся с этим подробнее. Ваши идеи и соображения что не так с кодом выше буду ждать в комментариях😊 На этом все, спасибо что дочитали до конца, до встречи!
Открыть канал и посмотреть медиаConcurrency and Consistency. Non-blocking, lock-free and async. Пост №3. Что существует кроме Lock-Free? Гарантии в блокирующей и неблокирующей синхронизации. В посте №1 я дал определение понятию lock-free. Дальше сразу пошёл разбирать ABA-проблему, и это было ошибкой. Всё-таки важный кусочек базы я упустил, поэтому делаю шаг назад. Когда мы пишем код, мы так или иначе ожидаем от него определённой степени корректности. В случае с программами, в которых есть блокирующие примитивы синхронизации, нам важно, чтобы: - Примитив обеспечивал эксклюзивный доступ к критической секции - это гарантия mutual exclusion и, по сути, гарантия безопасности нашего кода. - В нашем коде отсутствовали взаимоблокировки - это гарантия deadlock freedom. - Поток, намеревающийся попасть в критическую секцию, гарантированно попадал в неё за конечное время - это гарантия starvation freedom. За дедлоки обычно отвечает программист, гарантии отсутствия голодания обычно падают на рантайм языка программирования (потому что в нём реализован примитив синхронизации) и рантайм ОС, потому что он планирует исполнение потоков. А какие есть гарантии в неблокирующей синхронизации? - Гарантия отсутствия препятствий (Obstruction-free): если поток активен и у него нет конкурентов, он должен исполнять полезные инструкции, демонстрировать прогресс. - Гарантия отсутствия блокировок (Lock-free): наш код гарантирует, что в случае конкурентного исполнения кто-то обязательно достигнет прогресса. - Гарантия отсутствия ожидания (Wait-free): каждый поток завершает операцию за ограниченное число шагов, независимо от того, что делают другие потоки. Очень похожие определения, но немного другими словами, не находите? В следующих постах мы на примерах посмотрим, что скрывается за каждым красивым словом. P.S. Канал переходит в режим Wait-Free, теперь посты гарантированно будут публиковаться за конечное количество дней😁 Я вернулся.
Открыть канал и посмотреть медиаSolo los usuarios registrados pueden compartir su opinión.
¡Sé el primero en compartir tu experiencia con este recurso!
TürklenConocimiento de la historia y la identidad turcas.
Asesoramiento sobresitios y recursos útiles para computadoras e Internet.