17% скидка на размещение рекламы на площадках devby — до 20 ноября. Клац!
Support us

Непостижимая эффективность языка C

63 комментария
Непостижимая эффективность языка C

Не так давно издательство O’Reilly выпустило книгу «21st Century C: C Tips from the New School», которая собрала на Amazon.com довольно противоречивые отзывы. Поэтому я решил написать исключительно оптимистичный материал о «древнем языке» C и предлагаю обсудить его настоящее (а если желаете — прошлое и будущее).
Слово Дамьену Катцу, автору CouchDB. В настоящее время он является главным техническим директором (CTO) в Couchbase.

Много лет я всеми правдами и неправдами пытался расстаться с языком C. Слишком прост по составу, требуется управлять множеством деталей, слишком старый и неработоспособный, на первый взгляд — слишком низкоуровневый. Я крутил бурные и страстные интрижки с Java, C++ и Erlang. На всех этих языках у меня есть выполненные проекты, которыми я горжусь, но все эти языки в свое время разбили мне сердце. Они сулили что-то и не сдерживали обещаний, создавали культуры, в которых ты сосредотачиваешься не на том, на чем следует, а также требовали идти на катастрофические компромиссы, которые не оборачивались ничем, кроме горестных разочарований. И я на коленях приползал обратно к C.

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

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

Простота и выразительность

С — поразительно высокоуровневый язык. Да, я не оговорился, и повторю еще раз: C — фантастически высокоуровневый язык. Конечно, не такой высокоуровневый, как Java или C#, и далеко не такой, как Erlang, Python или JavaScript. Но он не менее высокоуровневый, чем C++, зато гораздо, гораздо проще. Разумеется, C++ предлагает больше абстракций, но эти абстракции недалеко ушли от C. Работая с C++, вы все равно должны в совершенстве знать C, а также еще кое-какую смешную дребедень.


Если кто-то вам скажет: «Мне нужен язык программирования, на котором мне всего лишь достаточно сказать, чего я хочу — и все будет готово», дайте ему карамельку».
Алан Дж. Перлис

Сложно вспомнить какие-нибудь низкоуровневые языки, которые могли бы заменить C на практике. Это объясняется тем, что C так чертовски успешно абстрагирует свойства той машины, на которой работает, и делает это на таком высоком уровне, что остальные низкоуровневые языки просто не нужны, если есть C. Язык C действительно хорош в том, для чего предназначается.

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

Язык C задал планку для по-настоящему хорошего низкоуровневого языка и избавился от всего, что этой планке не соответствует. Таким образом, С полностью перевернул представление о том, что такое «качественный низкоуровневый язык». Черт возьми, это впечатляет!

Более простой код, более простые типы

C — статически типизированный язык со слабым контролем типов, его система типов довольно проста. В отличие от C++ или Java, здесь нет классов, в которых требуется определять всевозможные новые варианты поведения типов, действующие во время исполнения. Вы работаете практически только со структурами и объединениями, и все вызывающие элементы должны предельно точно описывать, как они используют типы.

«Даром» вызывающая сторона не получает почти никакой информации.

«Вы хотели банан, но оказались наедине с гориллой, которая держит этот банан. А вокруг вас — джунгли».
Джо Армстронг


Иногда кажущаяся слабость оказывается преимуществом. Именно такова ситуация с API языка C: их «поверхностная область» кажется очень маленькой и простой. Вместо массивных фреймворков здесь делается ставка на хорошо прослеживаемые тенденции и культуру создания компактных библиотек, которые представляют собой легковесные абстракции простых типов.  
Сравните это с объектно-ориентированными языками, где в базах кода зачастую развиваются огромные взаимозависимые интерфейсы из сложных типов, где аргументы и возвращаемые типы оказываются сложнее. Такая сложность становится фрактальной: каждый тип является классом, определенным в контексте методов с аргументами и возвращаемыми типами, которые, в свою очередь, также могут быть сложными возвращаемыми типами.

Конечно, объектно-ориентированные системы типов не провоцируют такую фрактальную сложность сами по себе, но они повышают вероятность ее возникновения. В объектно-ориентированной среде проще пойти по неверному пути. C также не исключает возможности свернуть на кривую дорожку, но сделать это сложнее. В C обычно создаются более простые и неглубокие типы с меньшим количеством зависимостей. Они проще для понимания и для отладки.

Самый быстрый

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

«Если вы пытаетесь перехитрить компилятор, то практически сводите на нет его пользу».
Керниган и Плоджер, The Elements of Programming Style

Всякий раз, когда вам рассказывают о том, что на высокоуровневом языке, например, Java или Haskell, удалось достичь производительности «почти как на C» — изучите детали. В лучшем случае это окажется плоской шуткой. Таким «обгонятелям» приходится вытворять неуклюжие обратные сальто, пользоваться специальными знаниями об «умных» компиляторах и внутренних механизмах виртуальной машины, чтобы достичь сравнимой скорости. Обычно такие эксперименты приводят к тому, что простая и выразительная природа языка тонет в мудреных оптимизациях, специфичных для конкретных версий. Выигрыш в скорости обычно получается минимальным.

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

Способы оптимизации в C обычно просты и незатейливы. Конечно, встречаются сравнительно сложные случаи, но в таких ситуациях в вашем распоряжении будет масса профилировочных инструментов, которые помогут разобраться с проблемой без необходимости изучать подноготную виртуальной машины или «достаточно умный компилятор». При работе с профилировочными инструментами для процессора, памяти и ввода-вывода язык C подойдет идеально, так как вы будете четко видеть, что именно происходит. C сохраняет лидирующие позиции в скорости как на микроуровне, так и во всем стеке.

Ускоренные циклы сборки-запуска-отладки

Эффективность и продуктивность труда разработчика исключительно сильно зависят от цикла «сборка-запуск-отладка». Чем быстрее этот цикл, тем более интерактивна сама разработка и тем дольше вы остаетесь в движении, тратя время именно на решение задачи. C обладает наивысшей интерактивностью разработки среди всех широко распространенных статически типизированных языков.

«Оптимизм — это профессиональная болезнь всего программирования. Обратная связь — это лекарство от этой болезни».
Кент Бек

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

Вездесущие отладчики и удобные аварийные дампы

Практически в любой системе, куда вам может потребоваться портировать программу, найдутся готовые отладчики C и инструменты для аварийных дампов. Это бесценные вещи, если нужно быстро найти источник проблем. А проблемы будут.


«Ошибка, отсутствует клавиатура — для продолжения нажмите F1».

При работе с любым другим языком под рукой может не оказаться удобного отладчика, а иногда — хорошего инструмента для аварийного дампирования. Более чем вероятно, что вам когда-либо придется программировать те или иные сложные процессы, код для которых стыкуется с кодом на C. В таком случае, вам может потребоваться отладить интерфейс между кодом на C и другим языком. Контекст при этом зачастую почти отсутствует, работа становится тягостной, чреватой ошибками, а результат бывает совершенно неприменим на практике.

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

Вызывается отовсюду

В языке C есть стандартизированный бинарный интерфейс приложений (ABI), поддерживаемый всеми существующими операционными системами, языками и платформами. Он не требует ни среды времени исполнения, ни каких-либо иных неизбежных издержек. Таким образом, код, написанный вами на C, полезен не только для вызывающих элементов из C, но и для любой мыслимой библиотеки, языка или среды, какие только существуют в природе.

«Ключ к портируемости — немногочисленные концепции и полное описание».
Дж. Пальме

Код на C можно использовать в автономных исполняемых файлах, скриптовых языках, коде ядра, коде прошивок, в качестве DLL и даже вызывать из SQL. Это лингва франка системного программирования и подключаемых библиотек. Если вы хотите написать какой-то код только однажды и обеспечить его используемость в большинстве сред и ситуаций, то C — единственный разумный выбор.

Да, у него есть и недостатки

В C много «недостатков». В нем нет контроля границ, в памяти легко что-нибудь повредить, встречаются висящие указатели и утечки памяти/ресурсов, поддержка параллелизма прикручена кое-как, нет модулей и пространств имен. Обработка ошибок может быть страшно затруднительной и пространной. Легко допустить целый класс ошибок, о которые разбивается стек вызовов, а ваш процесс захватывается зловредным вводом. Замыкания? Смешно! 

«Если ничего не получается, прочтите инструкцию».
Л. Ласельо

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

Как-то раз в Couchbase нам довелось потратить более двух человеко-месяцев работы, чтобы справиться со сбоем в виртуальной машине Erlang. У нас ушла уйма времени на то, чтобы отследить одну проблему, которая коренилась в самом ядре реализации Erlang. Сначала мы вообще не понимали, что происходит и почему, думали, что ошибка в нашем подключаемом коде на C, безуспешно пытались ее найти и исправить. А оказалось, что в ядре Erlang есть баг, вызывающий условия гонки. Такая фундаментальная проблема возможна в любом языке.

Сначала, из соображений производительности, мы стали все активнее переписывать код Couchbase на C, именно на этом языке реализовали несколько новых фич. Но когда мы столкнулись с проблемами, оказалось, что их совсем несложно отлаживать и исправлять. Итак, в долгосрочной перспективе язык C более продуктивен.

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

Источник

Читайте также
«Эти вопросы — не ловушка». Как на собеседовании говорить о себе уверенно и честно
«Эти вопросы — не ловушка». Как на собеседовании говорить о себе уверенно и честно
«Эти вопросы — не ловушка». Как на собеседовании говорить о себе уверенно и честно
Собеседование — это не экзамен, а возможность показать, что вы подходите компании. Один из самых частых и в то же время самых сложных вопросов — «Каковы ваши сильные и слабые стороны?». Мы перевели для вас статью из блога Coursera и адаптировали её, чтобы помочь подготовиться к этому моменту без волнения и штампов.
Lingvanex выложил в открытый доступ модель для перевода с русского языка на беларусский
Lingvanex выложил в открытый доступ модель для перевода с русского языка на беларусский
Lingvanex выложил в открытый доступ модель для перевода с русского языка на беларусский
1 комментарий
Проста пачаць, лёгка выгараць. Студэнт перакладае культавую гульню на беларускую мову
Проста пачаць, лёгка выгараць. Студэнт перакладае культавую гульню на беларускую мову
Проста пачаць, лёгка выгараць. Студэнт перакладае культавую гульню на беларускую мову
Я даўно аматарскі займаюся перакладамі на беларускую мову. Мой новы праект — адаптацыя Project Zomboid, славутай камп’ютарнай гульні.
2 комментария
7 отличных курсов по финансам. Уплыть «с галеры» и основать свой стартап
7 отличных курсов по финансам. Уплыть «с галеры» и основать свой стартап
7 отличных курсов по финансам. Уплыть «с галеры» и основать свой стартап
Если вы посмотрели «Волк с Уолл-стрит» и хотите, как Леонардо ди Каприо прогуливаться по яхте с бокалом вина в руках, но не знаете, с чего начать, подборка курсов Digitaldefynd станет для вас отличным стартом. Здесь представлены как платные, так и бесплатные программы, которые помогут вам освоить финансовое моделирование. Они подойдут не только для начинающих слушателей, но и для экспертов.
1 комментарий

Хотите сообщить важную новость? Пишите в Telegram-бот

Главные события и полезные ссылки в нашем Telegram-канале

Обсуждение
Комментируйте без ограничений

Релоцировались? Теперь вы можете комментировать без верификации аккаунта.

Комментариев пока нет.