20 часов оптимизаций, вживую
Всем привет.
Я пишу код, временами мне это нравится, а иногда даже получается. Пока по миру не шарахнул карантин я временами выступал на каком-нибудь офлайновом мероприятии, меня слушали, а мне это нравилось. Но вот уже два года как планета погрузилась в карантинный строй; я привык думать, что мои коллеги не люди, а кружочки вписанные в прямоугольник в окне одной из коммерческих звонилок.
А славы и света софитов хочется-то!
Вот заходишь на ютуб и восхищаешься докладами и каналами других разрабов. Видишь эти сотни и тысячи просмотров и постепенно заражаешься идеей, что и сам так можешь.
И я попробовал.
За последние три месяца записал 10 двухчасовых стримов на темы которые разобрал за время своей карьеры. Получалось по-разному, стрим такой формат, где очень много может пойти не так, а я его еще и усложнил для себя лайвкодингом. Временами что-то шло не так, но, если честно, я даже удивлен, что за 20 часов эфира у меня не случилось ничего действительно катастрофического, после чего я бы стал искать кнопку «удалить канал» и гуглить смену фамилии.
Под катом немного об идеях с которыми я делал видео и немного текста про каждую из тем.
Идея. Почему делаю видео именно так.
Я уверен, что «знать» и «уметь» это разные вещи. Сколько раз я гордо перед клиентом бил себя в грудь, что знаю технологию и там все будет норм, ведь я прочитал три десятка великолепных статей на хабре про эту технологию. А потом почти месяц на ежедневном созвоне с гибнущей уверенностью в голосе, говорил, что вчерашнюю проблему решил, но возникла еще одна, надеюсь сегодня исправлю.
Дело в том, что когда читаешь статью, можешь думать, что понял материал, но на самом деле понял не верно. Будет хорошо сразу попробовать применить на практике то, что изучил, и, возможно, получить звонкую пощечину от реальности, которая довольно грубо может тыкнуть тебя в ошибки. Может быть и хуже: ты расскажешь кому-то про то как понял тему и людей в мире, тех кто понял ее не верно станет больше.
Но если ты написал код и своими глазами увидел как он работает, то скорее всего ты понял правильно, то что имели в виду в первоисточнике. А еще здесь не получится опустить детали. Знаете, тот момент, когда читаешь статью, там сначала рассказывают о чем-то простом, но при попытке повторить ты застреваешь на каком-то шаге. Как будто на лестнице забыли сделать несколько ступенек.
Мои видео это стримы, где я в живую пишу код и рассказываю, что он делает. Это совсем не тоже самое, что написать код самостоятельно, но это куда ближе к этому, чем статья. Да и я стараюсь готовиться к стримам, написать каждый пример, продумать что буду говорить, чтобы это не было похоже на реальную работу разраба из которой сложно сотворить шоу на ютубе: ведь иногда мы часами смотрим на один метод.
HTTP сервер на .NET 5 с пустого ConsoleApp
Стрим побился на две части, потому что на первом в моей жизни прямом эфире, посреди кодинга у меня лег интернет. К счастью, за 9 следующих видео такого форс-мажора не повторялось.
Бывают ситуации, когда неплохо знаешь как работают высокоуровневые компоненты, знаешь как работают низкоуровневые, но абсолютно не понимаешь как из одних собрать другие. Готовясь и проводя этот стрим как раз разобрался, как собрать собственный полноценный многопоточный HTTP сервер, начиная с TCP уровня. В .NET это классы TcpListener/TcpClient. Кроме этого, в довесок, сделал нехитрую библиотечку для контроллеров.
Оптимизация C# кода! BenchmarkDotNet, низкоуровневые диагностики
Иногда мы выясняем, что какой-то метод в приложении тормозит. Иногда мы сразу знаем как его переписать, чтобы он перестал тормозить, а иногда нет. Но в обоих случаях нам интересно насколько же мы его разогнали. В мире .NET есть чудная библиотека, которая умеет очень точно с кучей полезной статистики замерять время выполнения кода, даже если это время всего несколько наносекунд. Кроме того, она посчитает еще множество статистик, которые дадут больше информации о том, хороший бенчмарк вы написали или нет и о характере выполнения вашего кода.
Разбирал такие штуки:
Почему среднее время выполнения теста плохая метрика?
Би/Мультимодальность распределения, что с ним делать?
Пример бенчмарка и обоснование его кошмарности.
Профилировка .NET приложений. Разбор тестового задания Senior .NET
Я хотел сделать стрим про использование dotTrace, но довольно сложно найти пример, проблему которого, можно объяснить достаточно быстро. Тут на помощь пришел друг, который рассказал про тестовое:
Нужно написать 2 программы, одна генерирует большие файлы в заданном формате, другая умеет их сортировать по определенным правилам. RAM ограничена, а файлы могут быть и по 100GB.
У dotTrace крутой интерфейс, где очень удобно отображены десятки параметров выполнения, но во время первых использований довольно трудно разобраться куда же смотреть. Хочу верить, что кому-то помог с этим сделав стрим.
Профилировка памяти в dotMemory! Режем потребление памяти, ищем утечки, анализируем memory traffic.
Было очевидно куда двигаться после обзора CPU Profiler`а. Нужно было рассказать про работу с профилировкой памяти, анализом трафика и о возможных проблемах. Здесь мне не подвернулся такой емкий и удачный пример, но смог собрать несколько интересных. Как и в прошлый раз: dotMemory отображает очень много разной информации и в ней легко запутаться. Думаю это видео может немного подсказать, куда смотреть.
Сложность алгоритма на коленях перед архитектурой процессора! LinkedList в в исходниках .net 6
Заценили как я прокачался в кликбейтных заголовках?
На такую желтизну пришлось пойти не от хорошей жизни. Мне понравился этот стрим, у меня корректно отработали все примеры, не было никаких серьезных сбоев, а в момент трансляции его смотрело едва ли 3 человека, в то время как прошлые смотрели 10–15.
Почему мне показалось интересным про это рассказать?
Структура Связанный список с одной стороны хорошо известна большинству разработчиков, на бумаге у нее прекрасные характеристики, а используем ее мы совсем не часто.
Есть мнение, что она тормознутая и нужно всегда использовать обычный List, что в .NET построен поверх массива. И в этих словах есть доля правды. Связано это с устройством оперативной памяти и кешами процессора. Я придумал с десяток примеров, что проверяют границы применимости обоих списков, а заодно была возможность показать несколько очень низкоуровневых hardwar«ных diagnoser«ов из библиотеки BenchmarkDotNet.
Истории про оптимизации, которые сработали в production
Дело было под Новый Год и я подумал сделать более легкий выпуск. Я отошел от livecoding«а и поделился разными кейсами по оптимизации приложений, которые приходилось применять на разных проектах. Итак, о чем было:
как сделал приложение, для отображения главной страницы которого уходило 2000 запросов на бедный MySQL;
Как разрабатывая IDE мы пытались ускорить открытие нового документа;
Как программа для построение блок-схем из исходного кода сожрала 12ГБ оперативной памяти;
И еще несколько интересных историй.
Внутреннее устройство рантайма .NET: Устройство объекта в памяти, JIT и дизассемблер
Про устройство рантайма написано многое, но как бы там ни было еще раз все это проговариваю: ссылка на объект типа, ссылка на блок синхронизации и прочее. Мне кажется, что ценность этого видео в том, что показываю много инструментов, которые, вероятно, не все видели и использовали чтобы показать как можно посмотреть на все эти штуки в реальности, в момент отладки приложения.
Вмешиваемся в вызов методов. Как работают виртуальные методы? Как работает JIT? С# — IL — ASM
Это видео дополняет и продолжает предыдущее. Там я почувствовал, что уже начинаю терять голос и не вытяну рассказывать весь заготовленный материал, поэтому отложил на неделю. Здесь как раз разобрал:
Как происходит вызов метода;
Чем отличается вызов обычного метода от вызова виртуального на уровне ASM и куда смотреть, чтобы увидеть эту разницу;
Как переопределить метод, что помечен как sealed или вообще конструктор класса string;
Зачем могут пригодится вышеописанные извращения
Как написать Full Text Index с нуля? Так работает Elastic Search и Full Text Search SQL Server
Этот стрим — лайвкодинг с нуля полнотекстового индекса с набором бенчмарков, чтобы померить сколько принес каждый трюк. Я долго по крупицам собирал инфу для этого стрима, придумывал примеры и не уверен, что где-то еще существует что-то подобное в одном месте.
К сожалению, здесь я местами ошибся в тактике: я где-то долго объяснял простые вещи, а потом был вынужден вообще пулей пролететь более сложные. Возможно, однажды перезапишу этот стрим.
Самый быстрый поиск подстроки. Префиксные и суффиксные деревья. (Prefix/Suffix trees, trie)
Продолжая тему работы с текстом я решил остановится на паре специализированных структур. Тем более все равно упомянул их в прошлом ролике.
Здесь удалось:
Написать с нуля префиксное и суффиксное дерево;
Задизайнить и запустить ряд бенчмарков для понимания границ применимости этих структур;
Посмотреть сколько оперативной памяти в реальности могут занимать подобные структуры данных.
Microsoft SQLServer Query Performance: testing, tuning, tools. Query Plans, Query Store
На момент написания статьи этот стрим еще не состоялся. Он запланирован на четверг 17 декабря. Я на этом стриме буду гостем. Проведет его Сергей Сыроватченко (aka @AlanDenton которого хабр знает и любит его статьи.
Буду рад комментариям, как по технике, так и по форме. К сожалению, на ютубе очень не хватает обратной связи, что приводит к большому количеству сомнений по поводу того, чем занимаюсь.