Интервью с Энтони Уильямсом

Сегодня у меня в гостях Энтони Уильямс, автор недавно вышедшей книги “C++ Concurrency in Action”. Он живет и работает в Западном Корнуэлле, Великобритания, и из окон его офиса можно увидеть море. Энтони занимается библиотеками для С++, в частности boost::thread, принимает участие в работе над стандартом С++ и попутно работает в своей собственной компании “Just Software solutions”.

Я недавно приобрел его книгу о многопоточности в С++. Если честно, я пока не встречал лучшего материала по модели памяти в C++ 2011. Сейчас у нас возможность задать Энтони несколько вопросов, в частности про С++.

Предупреждение: Данная статья является переводом с английского. Я не профессиональный переводчик, поэтому в тексте могут встречаться мелкие неточности. Желающие всегда могут прочитать оригинал на английском.


До тех пор, пока многопоточный код не будет очевидно быстрее, создание однопоточного кода избавит вас от значительной головном боли.


Здравствуйте, Энтони, спасибо, что согласились дать интервью. Разрешите мне начать издалека. Программирование, компьютеры, С++… Почему вы решили этим заниматься? Что привело вас на путь битов и байтов.

Я всегда интересовался компьютерами. И к тому же у меня получалось. Дома у нас был Sinclair ZX81 и BBC Micro в школе, когда мне было 7-8 лет, и вот там все и началось. Разбирался с играми, пытаясь понять, как они работают. Когда пришло время устраиваться на работу после учебы, я уже весьма четко представлял, что буду заниматься программированием. Это приколько, интересно, заставляет думать, и тебе еще за это платят.

Я подозреваю, что С++ не был первым языком программирования, который вы выучили. Приходилось программировать на необычных языках поначалу?

С++ там не было, когда я начал программировать, поэтому это мой не первый язык. Я начал с Бейсика. Все домашние компьютеры снабжались разновидностями Бейсика, и тогда я еще не знал, что существует что-то иное. Некоторые программы были в машинных кодах, и я научился переводить на них язык ассемблера Z80 и вводить из в виде операторов DATA в программе-загрузчике на Бейсике.

Не думаю, что я программировал на чем-то по-настоящему необычном, хотя приходилось поработать на многих языках и на разнообразных системах. Программировать на PICе, имея только 100 байт на код, было непросто, и я подозреваю, не много людей программировали Psion Organizer II, хотя язык программирования там был во многом близок к Бейсику.

Можете вспомнить какие-то значительные или может даже выдающиеся книги, которые повлияли на вас в карьере?

Хм… Это могло быть описание программирования для Z80, когда мне было 10-11 лет. Не могу вспомнить ее названия, но я буквально вызубрил эту книгу. Я помнил каждую инструкцию, включая шестнадцатеричные коды и количество тактов процессора. Я нашел схожее описание для 8086 на диске от PC, распечатал его и также вызубрил.

Сейчас у меня на полке стоят, например, Design Patterns, Refactoring, и The Art of Computer Programming, хотя я все еще люблю быть поближе к железу, например, с Intel’s Software Optimization Cookbook.

Теперь С++ и многопоточность. Было бы неразумно упустить возможность спросить про это у эксперта. Для начала: есть что-то в С++ 2011, что вам не нравиться в плане поддержки многопоточности?

Хороший вопрос! Сходу не могу назвать ничего, про что бы сказал “Мне не нравится, как это сделано”. Немного огорчает, что функция “is_ready()” была удалена из future и shared_future. Хотя ее можно реализовать через wait_for(seconds(0)).

Вы мейнтейнер библиотеки boost::thread. Одновременно с этим вы разрабатываете собственную библиотеку, just::thread. Что в ней такого особенного?

Just::Thread - это строгая реализация библиотеки потоков C++ 2011, значительно оптимизированная для каждой платформы, тогда как в Boost.Thread отдается предпочтение переносимости, и местами ее интерфейс и семантика отличаются от Стандарта. Например, до сих пор отсутствует std::async, который реализован в Just::Thread.

Just::Thread также имеет специальный режим сборки для выявления deadlock’ов.

Actor’ы и идея разделение ресурсов через сообщения. В С++ 2011 их явно их не хватает. Можете порекомендовать библиотеку, где эта функциональность есть?

Just::thread Pro, которая сейчас на стадии разработки, реализует Actor’ы. В моей книге есть пример использования очередей сообщений для создания кода в стиле Actor’ов.

Я помню ваше высказывание, что целесообразность использования многопоточности может быть нетривиальна, так как смысл в ней начинает появляться только с определенного объема данных. Можете посоветовать, как решить - стоит ли озадачиваться многопоточностью в каком-то конкретном случае, или нет?

Да, надо всегда принимать во внимание накладные расходы при многопоточности. Если какая-то задача и так работает достаточно быстро, то лучше ее так и оставить однопоточной. До тех пор, пока многопоточный код не будет очевидно быстрее, создание однопоточного кода избавит вас от значительной головном боли.

Как и всегда – ключевая идея оптимизации производительности (а тут мы рассматриваем многопоточность именно как оптимизацию) - это профилирование приложения. Где больше всего тратиться времени? Как можно распараллелить? Джейсон МакГинесс (Jason McGuiness) продемонстрировал на ACCU 2012, что если распараллелить не ту часть приложения, то много сил уйдет впустую без ощутимого результата.

Давайте теперь поговорим о TDD. Используете ли вы Test Driven Development? Применимо ли это для разработки многопоточных библиотек, например, для C++

Я люблю TDD и стараюсь использовать этот подход все время. Это стимулирует работу небольшими шагами, а набор уже разработанных тестов гарантирует, что существующий функционал “не сломан” новым кодом.

Для многопоточных библиотек применение TDD может быть не совсем прозрачно, но все же возможно. Главное, это выстроить код так, чтобы тестировать то, что нужно. Обычно, требуется что-то по типу барьера (я часто использую std::promise и std::share_future), когда подготавливаете потоки в нужно состояние и говорите “поехали!”. Лучший способ тестирования многопоточного кода — это убрать многопоточность. Вместо этого обеспечить прозрачные механизмы обмена между потоками, и тестировать их по отдельности.

Считаете ли вы, что код обязан быть безупречным, без компромисов к неаккуратности или отсутствия красоты? Как вы решаете для себя, когда код готов к релизу или нет?

Всегда стоит стремиться, чтобы код бы идеален. Если этого не делать, то это обычно заканчивается корявым немодифицируемым кодом.

Однако, не всегда получается писать идеальный код. Порой не ясно, как можно сделать лучше, или надо очень много времени на изменения. Всегда лучше иметь код, которые работает правильно, нежели который выглядит красиво. Если есть достаточно тестов, то можно поработать над красотой кода позже, без опаски что-нибудь сломать.

Я лично сужу о готовности кода по невозможности найти потенциальных путей его сломать. Если таковы пути находятся, я пишу тест и исправляю проблему.

Можете назвать три самый больших “Никогда этого не делай!” для программистов? на С++?

Хех, “Никогда” – это сильное слово.

Вот некоторые вещи, которые не стоит сделать часто (в произвольном порядке):

  • Использование глобальных переменных. Передавайте все как параметры или используйте члены класса вместо глобальных переменных, так как они делают код сложным для понимания.

  • Использование синглтонов. Опять, это глобальные переменные, которых следует избегать.

  • Написание многопоточного кода без тщательного продумывания методов доступа к данным их разных потоков. На это стоит потратить время, так как оно окупится в далекой перспективе.

Конкретно для С++, не стоит часто:

  • Использовать malloc и free. Это С++, я не С.

  • Писать код, требующий использования “delete”. Если вам приходится использовать “new”, то стоит использовать умные указатели, например, std::shared_ptr или std::unique_ptr для управления памятью. Также часто лучше просто взять std::vector для хранения чего угодно.

  • Перегружать операторы нетрадиционным образом. Иногда это может быть действительно удобно (например, << для вывода в поток), но если a+b значит что-то отличное от сложения, то это прямой путь все запутать.

Вы написали книгу. Можно об этом немного поподробнее. Сколько времени заняло создание “C++ Concurrency in Action”, и почему вы вообще решили взяться за ее написание? Что было самым трудным?

С книгой просто все удачно сложилось. Я плотно занимался сообразными главами стандарта С++ и оказался в нужном месте в нужное время.

В итоге, все заняло четыре года. Так как стандарт еще на был принят, когда я начал писать книгу, мне приходилось перерабатывать главы по мере изменения стандарта. Хотя и без этого это была весьма объемная работа. Самым непростым было переписывать некоторые глава после получение отзывов.

Можете порекомендовать еще книги про многопоточность и многозадачность?

“Patterns for Parallel Programming” от Mattson, Sanders и Masingill является хорошим обзором по созданию параллельных программ.

“The Art of Multiprocessor Programming” от Herlihy и Shavit тоже неплохо, но более на низком уровне. Тут описываются такие понятия, как видимость, атомарность и согласованность, и реализация низкоуровневых структур таких как очереди, спин-блокировки и мониторы.

А теперь вопрос, который я спрашиваю всех: спортивное программирование и соревнования по программированию. Важно но ли для любого разработчика регулярно тренироваться в решении алгоритмических задач? И приходилось ли вам разрабатывать или реализовывать замысловатые алгоритмы?

Я люблю всякие задачки. Если разобраться, программирование по себе является большой одной задачей, что и делает его интересным.

Я думаю, головоломки требуют схожего мыслительного процесса как и программирование, поэтому регулярное их решение положительно повлиять на “умение” программировать. Любая практика в чем-либо всегда полезна, и задачи и соревнования по программированию позволяют вырваться из привычных шаблонов и попробовать что-то еще. Мне нравится “Intel Threading Challenge” последние пару лет. Даже не учавствуя напрямую, полезно поработать с задачами – это забавно и реально заставляет задуматься.

Я получил большое удовольствие, работая над алгоритмом, помогающим вертолетным инженерам проводить обслуживание. Они снимали показания с вертолета, используя специальное оборудование в процессе полета при разных условиях. Затем программа анализировала пути улучшения полета. Так как реальные полеты на вертолете дороги, была задача настроить вертолет за минимальное количество пробных полетов.

Вы предпочитаете IDE или vi/make? Возможно ли все еще, используя vi, создавать программное обеспечение современного уровня сложности, или среды разработки являются неизбежным шагом для создания программ промышленного уровня?

Я использую emacs и make. Я пока еще не нашел среды разработки лучше. Уверен, что в Eclipse/СDT очень много потенциала, особенно благодаря усилиям команды Питера Соммерлада, но для меня этого пока недостаточно.

Существует ли идеальный язык программирования? Может ли он вообще существовать? Может это C++?

Всегда есть моменты, которые можно было бы улучшить в любом языке. Не думаю, что идеальный язык существует. Если удастся создать достаточно развитый искусственный интеллект, то мы в итоге придем к использованию естественных языков, нежели языков программирования. Но, я думаю, до этого еще далеко.

Давайте поговорим о найме на работу. Если вам надо нанять хорошего С++ программиста, какие вопросы вы бы спрашивали?

В некотором роде это зависит от того, для чего именно я нанимаю. Если есть время обучить человека, то конкретные знания по С++ не проблема, и я бы сфокусировался на том, что называется “общие способности”.

Если же требуется кто-то, знающий С++, можно и конкретно по С++ спросить.

Под занавес, можете назвать три вещи, которые, по вашему мнению, каждый разработчик просто обязан написать?

Не совсем уверен про три вещи для каждого разработчика, но однозначно стоит попробовать реализовать базовые структуры данных, например, список или хеш. Пусть это будет номер один.

Второе, я думаю, что парсер языка может дать хорошее понимание того, как надо использовать структуры данных, даже если это парсер для разбора простого конфигурационного файла, а не языка типа С++. Например, парсер арифметических выражений может быть неплохим упражнением.

И наконец, я думаю, стоит написать клиент-серверное приложение. Например, вэб-приложение на JavaScript, работающее в браузере, и что-то на северной стороне. Хотя любая задача, где делаются вызовы со стороны клиента к серверу также подойдет. Суть тут в том, что удаленные вызовы всегда заметно дороже локальных, поэтому придется подумать о накладных расходах при создании такого интерфейса. Если речь идет о пользовательском интерфейсе, то это может быть упражнением для минимизации задержек на сервере, что бы интерфейс не “замирал”.

Спасибо, Энтони, за интервью. С нетерпением ждем ваших новых выступлений и книг, и появления на конференциях

// Энтони Уильямс, Александр Дёмин

// Июль 2012


Disclaimer

Комментарии