[Из песочницы] Почему вы должны изучить Go?

Всем привет! Представляю вашему вниманию мой перевод статьи (включая графики) Кевала Патела Why should you learn Go? Статья содержит много интересных фактов, которые, по моему мнению, будет полезно узнать новичкам в Go.

P.S.: Статья, как и большинство статей, на мой взгляд, отражает опыт и мнение автора, которое может не совпадать с вашим, и это нормально — сколько людей, столько и мнений.

Gophers

Изображение взято с ресурса kirael-art.deviantart.com/art/Go-lang-Mascot-458285682
«Go станет серверным языком будущего.» — Tobias Lütke, Shopify

За последние пару лет произошёл мощный рост нового языка программирования: Go, или Golang. Согласитесь, ничто так не может свести с ума разработчика, как новый язык программирования. Поэтому, я начал изучать Go 4–5 месяцев назад и вот что я могу сказать о том, почему вы должны изучить этот новый язык.

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

Ограничения железа:


Закон Мура не работает.

Первый процессор Pentium 4 с тактовой частотой 3.0 ГГц был представлен ещё в 2004 году компанией Intel. Сегодня, мой Macbook Pro 2016 имеет тактовую частоту 2.9 ГГц. Таким образом, около десятилетия нет особого прогресса чистой вычислительной мощности. Ниже на графике, вы можете увидеть сравнительный график роста вычислительной мощности по времени.

Сравнительный график роста вычислительной мощности по времени

По графику можно понять, что однопоточная производительность и частота процессора оставалась стабильной почти десятилетие. Если вы думаете, что добавить больше транзисторов — это хорошее решение, то вы ошибаетесь. Так происходит потому, что в более меньших масштабах начинают проявляться квантовые свойства объекта (такие как туннелирование, [или туннельный эффект. — прим.перев.]), а добавление большего количества транзисторов действительно может привести к дополнительным расходам (почему?) и количество транзисторов, которые вы можете добавить за один доллар стремительно начинает падать.

Поэтому, для решения проблемы выше,

  • Производители начали добавлять больше ядер в процессор. На текущий день нам доступно 4-х и 8-ми ядерные процессоры.
  • Также положено начало гиперпоточности.
  • Добавили больше кэша в процессор для увеличения производительности.

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

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

«Современные процессоры похожи на забавные автомобили, заправленные нитро, — они превосходны в гонке на четверть мили. К сожалению, современные языки программирования, как трасса Монте-Карло — полны изгибов и поворотов.» —  David Ungar

В Go есть горутины !


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

Но большинство современных языков программирования (такие, как Java, Python) пришли из однопоточной среды разработки 90-х. Хотя большинство этих языков поддерживают многопоточность, но реальная проблема связана с одновременным выполнением, блокированием потока, состоянием гонки и тупиковой ситуацией. Эти вещи осложняют создание многопоточного приложения на вышеназванных языках.

Например, создание нового потока в Java неэффективно использует память. Поскольку каждый поток потребляет примерно 1МБ памяти из кучи (динамически распределяемой памяти. — прим. перев.) и в итоге, если вы запустите тысячи потоков, то они окажут колоссальное давление на память и могут вызвать завершение работы приложения из-за её нехватки. К тому же, если вы хотите, чтобы два или более потока могли общаться между собой, то сделать это будет довольно трудно.

С другой стороны, Go был выпущен в 2009 году, когда многоядерные процессоры были уже доступны. Вот почему Go был создан с учётом многозадачности (concurrency. — прим. перев.). Go использует горутины вместо потоков. Они потребляют почти 2КБ памяти из кучи. Поэтому, вы можете прокручивать хоть миллионы горутин в любое время.

Как работают горутины?

Как работают горутины? Подробнее: golangtutorials.blogspot.in/2011/06/goroutines.html

Другие преимущества:

  • Горутины имеют расширяемые сегментированные стеки. Это означает, что они будут использовать память только по необходимости.
  • Горутины имеют более быстрое время запуска, чем потоки.
  • Горутины поставляются со встроенными примитивами для безопасного обмена данными между собой (каналы).
  • Горутины позволяют избежать необходимости прибегать к блокированию мьютексов при совместном использовании структур данных.
  • Также, горутины и потоки ОС не имеют сопоставления 1:1. Одна горутина может запускаться во множестве потоков. Горутины сжаты (multiplexed. — прим.перев.) в малое количество потоков ОС.

Вы можете посмотреть отличное выступление Роба Пайка Многозадачность — это не параллелизм, чтобы более глубоко разобраться в этой теме.

Все вышеупомянутые пункты делают Go очень мощным для обработки многозадачности так же, как в Java, С и С++, и в то же время сохраняя красоту и естественность кода, как в Erlang.

График многозадачности против эффективности
Go вобрал в себя лучшее из обоих миров. Одновременно лёгкий в написании и эффективный в управлении многозадачностью

Go запускается непосредственно на железе.


Одно из самых значимых преимуществ использования С/С++ вместо современных языков, типа Java/Python, это их производительность. Потому что С/С++ компилируются, а не интерпретируются.

Процессоры понимают только двоичный код. Как правило, когда вы пишете приложение на Java или других, основанных на JVM, языках, то при компиляции вашего проекта, он компилируется с человекопонятного кода в байт-код, который понятен для JVM или другой виртуальной машине, которая запускается поверх ОС. При выполнении, VM интерпретирует этот байт-код и конвертирует его в двоичный код, понятный процессору.

Этапы выполнения кода, основанных на JVM
Этапы выполнения кода, основанных на JVM

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

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

Go вобрал лучшее из обоих миров. Как и низкоуровневые языки, типа С/С++, Go компилируемый язык. Это подразумевает производительность, близкую к низкоуровневым языкам. Он также имеет свой сборщик мусора для распределения и удаления объектов. Больше malloc () и free ()! Круто!

Код, написанный на Go, легко поддерживать.


Позвольте мне сказать вам одну вещь. У Go нет такого безумного синтаксиса, как в других языках, — всё очень аккуратно и чисто.

Разработчики Go в Google имели это ввиду, когда создавали его. Ввиду того, что у Google огромная кодовая база и над ней трудятся тысячи разработчиков, то код должен быть простым для понимания остальными разработчиками, и один участок кода должен иметь минимум побочных эффектов на другие участки. Это делает код более простым для поддержки и внесения изменений.

Go намеренно не содержит множество особенностей ООП языков.

  • Нет классов. Каждая вещь делится только на пакеты. Вместо классов Go использует только структуры (structs. — прим.перев.).
  • Не поддерживает наследование. Это упрощает модифицирование кода. В других языках, типа Java/Python, если класс ABC наследует класс XYZ, и вы при этом делаете какие-то изменения в классе XYZ, то это производит дополнительное изменения во всех наследованных от него классах. К тому же, без наследования, код Go становится более простым для понимания (так как нет super классов, на которые нужно обращать внимание при изучении участков кода).
  • Нет конструкторов.
  • Нет аннотаций.
  • Нет дженериков (универсальных шаблонов. — прим.перев.).
  • Нет исключений.

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

График читабельности кода против его производительности
Читабельность кода против его производительности.

График выше показывает, что Go почти так же эффективен как С/С++, и имеет такой же простой синтаксис, как Ruby, Python и другие языки. Это беспроигрышный вариант (win-win. — прим.перев.) как для людей, так и для компьютера!

Синтаксис Go очень стабилен, чего не скажешь о другом новом языке Swift. Синтаксис не изменился с момента его публичного релизе версии 1.0 в 2012 году. Это наделяет его обратной совместимостью.

Go поддерживается Google.


  • Я знаю, что это не совсем техническое преимущество. Но Go разработан и поддерживается Google. У Google самая большая облачная инфраструктура в мире и она всё ещё расширяется. Google создала Go для решения их собственных проблем с поддержкой масштабируемости и эффективности. С этими же проблемами вам придётся столкнуться и при создании своего собственного сервера.
  • Более того, Go используется такими компаниями, как Abode, BBC, IBM, Intel и даже Medium. (Источник: github.com/golang/go/wiki/GoUsers)

Заключение:


  • Хотя Go отличен от других ООП языков, это всё тот же зверь. Go предоставляет вам такую же высокую производительность, как в С/C++, высокоэффективную обработку многозадачности, как в Java и такое же удобство написания кода, как в Python/Perl.
  • Если вы не планируете изучать Go, то я всё же скажу, что лимит аппаратного обеспечения оказывает давление на нас, разработчиков ПО, которые хотят писать очень эффективный код. Разработчику нужно понять железо и соответственно оптимизировать свою программу. Оптимизированное ПО можно запустить на дешёвом и медленном устройстве (типа IOT), что в целом лучше влияет на опыт взаимодействия конечного пользователя (UX. — прим.перев.).

Комментарии (6)

  • 18 апреля 2017 в 16:36

    +4

    1) «you should» != «вы должны»
    2) беглое прочтение статьи показывает что из всего перечисленного для Go уникальным является только «Go поддерживается Google.», это (без иронии) мощный агрумент.
  • 18 апреля 2017 в 16:47 (комментарий был изменён)

    +3

    Изображение «Красота и естественность кода» мне кажется очень холиварная.
    Тоже самое могу сказать и про изображение «Эффективность и производительность для компьютера»
  • 18 апреля 2017 в 16:53

    +2

    Go запускается непосредственно на железе

    Rust тоже.


    Код, написанный на Go, легко поддерживать.

    Сложно назвать легко поддерживаемым код на языке, в котором можно случайно забыть написать «if err!= nil». Rust за это надаёт по ушам ещё при компиляции, да даже C++ выкинет исключение во время работы.


    Классов в Rust нет, наследования нет, конструкторов нет, исключений тоже нет (про остальное точно не помню)


    Go почти так же эффективен как С/С++

    Rust тоже


    Синтаксис Go очень стабилен

    Подозреваю, синтаксис Rust ещё более стабилен)


    Go поддерживается Google

    Rust поддерживается Mozilla и целым сообществом и используется много кем


    Горутины, думаю, можно заменить на Futures и в будущем async/await.


    А ещё у Rust zero-cost abstractions и отсутствие gc.


    И почему же мы должны учить Go, а не Rust? :)


    (на правах вброса:)

    • 18 апреля 2017 в 17:00 (комментарий был изменён)

      0

      Сложно назвать легко поддерживаемым код на языке, в котором можно случайно забыть написать «if err!= nil».

      Ну, вроде как, Go все же возмутится за неиспользование переменной err на уровне сборки.


      И почему же мы должны учить Go, а не Rust? :)

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

  • 18 апреля 2017 в 16:55

    0

    Как круто, автор наконец изобрел универсальную объективную метрику «красоты и естественности кода»! Ну вот теперь заживем, теперь-то узнаем, кто говнокодит, а кто рефакторингом занимается! Интересно, в чем она измеряется, в сусликах/1k LOC, или еще как-то? Хотелось бы так же узнать точные значения для js/perl/python/ruby и прочих неудачников из левого нижнего угла, чтоб выяснить раз и навсегда, кто наименее отстойный.

  • 18 апреля 2017 в 16:55

    0

    , а что у Go с поддержкой GTK3? Гугл сказал, что пока не очень. Может я и ошибаюсь. Но переписывать все под другой язык, только потому, что он лучше, как-то влом…

© Habrahabr.ru