Предлагаю вашему вниманию перевод статьи Go from PHP engineer's perspective с сайта sobit.me.

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

Уже много лет выбор многих компаний падает на PHP для создания полноценных монолитных приложений. Более того, за последние 5 лет фреймворки (Symfony, Laravel, Zend), инструменты (Composer, Monolog) и стремительно растущее сообщество (PHP-FIG) помогли многим разработчикам в создании программного обеспечения на уровне предприятий. Многие компании, такие как Facebook, Yahoo!, Wikipedia, Wordpress, Tumblr, начинали свою историю с PHP, и это не помешало им стать успешными в последующие годы.

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

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

PHP и микросервисы


Каждый PHP разработчик знает, что, если ему удастся довести время инициализации большого монолитного приложения до 30мс, это отличный результат! Добавить к этому 50-100мс для обработки самого запроса, и перед нами поразительное общее время ответа.

Так как мы планируем разбить наш монолит, что произойдет, если мы решим придерживаться подобной архитектуры и для наших сервисов? Простые вычисления, и мы уже тратим 300мс только на инициализацию, если сервисы обратились друг к другу 10 раз в течение единого запроса. Неприятный пользовательский опыт!

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

Встречайте Go


Из Википедии:

Go (часто также Golang) — компилируемый, многопоточный язык программирования, разработанный компанией Google. Первоначальная разработка Go началась в сентябре 2007 года, а его непосредственным проектированием занимались Роберт Гризмер, Роб Пайк и Кен Томпсон занимавшиеся до этого проектом разработки операционной системы Inferno. Официально язык был представлен в ноябре 2009 года.

Go был разработан в Google. Он не был веселым 20%-ным проектом, также он не был предназначен добиться чего-то, недоступного другим. Его создали всего лишь из-за разочарования от сложности, которую создавали очень большие команды, работая над очень большими частями приложения на языках с большим набором возможностей.

Несмотря на такие замечательные черты, как легкий параллелизм или быстрая компиляция, основная черта, делающая язык особенным, — это невероятная простота. К слову, количество ключевых слов в Go — 25, в то время, как в PHP их насчитывается 67.

Go появился примерно в то же время, когда PHP получил поддержку пространства имен (2009). Спустя лишь 6 лет на нем созданы дюжины великолепных проектов, среди прочих Docker, Kubernetes, etcd, InfluxDB. Множество компаний, таких как Cloudflare, Google, Dropbox, SoundCloud, Twitter, PayPal, доверяют ему при написании своих бэкенд систем.

Возвращаясь к микросервисам


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

Go приложения быстро компилируются в машинный код. Многие люди твердят, что время компиляции настолько быстрое, что за то время, пока они переключаются в браузер и нажимают "Обновить", приложение уже перекомпилировано, перезапущено и обрабатывает запрос. Даже в больших базах кода присутствует ощущение, что работаешь с интерпретируемым языком, прямо как с PHP.

Традиционный "Hello, World!" API укладывается в 10 строк кода и отвечает быстрее миллисекунды. Возможности использования всех ядер процессора позволяет разработчикам параллельно запускать сложные части приложения. Экосистема позволяет выбрать любой транспортный протокол, например JSON по HTTP, gRPC, Protocol Buffers или Thrift. Запросы легко прослеживаются в Zipkin. Метрики экспортируются в различные бэкенды, от statsd до Prometheus. Есть возможность ограничить пропускную способность запросов с помощью ограничителей и защитить общение клиент-сервис с помощью прерывателей.

Больше о Go


Язык


Go — язык сильной типизации, что заставляет указывать тип переменной при ее объявлении:

var name string = "sobit"

Переменные могут определять тип по присваемому значению. Код выше аналогичен упрощенной версии:

var name = "sobit"

// или еще проще:

name := "sobit"

Теперь давайте вспомним, как мы меняем значения двух переменных в PHP:

<?php

$buffer = $first;
$first = $second;
$second = $buffer;

И эквивалент в Go:

first, second = second, first

Это возможно, благодаря множественным возвращаемым значениям. Пример с функцией:

func getName() (string, string) {
    return "sobit", "akhmedov"
}

first, last = getName()

В Go коде вы не найдете привычных foreach, while и do-while. Они объединены в единый оператор for:

// foreach ($bookings as $key => $booking) {}
for key, booking := range bookings {}

// for ($i = 0; $i < count($bookings); $i++) {}
for i := 0; i < len(bookings); i++ {}

// while ($i < count($bookings)) {}
for i < len(bookings) {}

// do {} while (true);
for {}

Несмотря на то, что в Go нет так называемых "классов" или "объектов", в нем присутствует тип переменной, который соответствует тому же определению, где структура данных объединяет код и поведение. В Go это называется "структурой". Проиллюстрируем на примере:

type rect struct { // объявляем структуру
    width  int
    height int
}

func (r *rect) area() int { // объявляем функцию структуры
    return r.width * r.height
}

r := rect{width: 10, height: 15} // инициализация
fmt.Print(r.area())

Иногда бывает полезным создавать и сложные структуры. Например:

type Employee struct {
    Name string
    Job  Job
}

type Job struct {
    Employer string
    Position string
}

// и инициализиция
e := Employee{
    Name: "Sobit",
    Job: {
        Employer: "GetYourGuide",
        Position: "Software Engineer",
    },
}

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

Горутина имеет простую модель: это функция, выполняемая параллельно с другими горутинами в едином адресном пространстве. Когда вызов завершается, горутина тихо выходит. Простейший пример — создать функцию сердцебиения, которая выводит на экран сообщение "Я жив" каждую секунду:

func heartbeat() {
    for {
        time.Sleep(time.Second)
        fmt.Println("I'm still running...")
    }
}

Как нам теперь запустить ее в фоновом режиме, чтобы при этом иметь возможность продолжать выполнять другие задачи? Ответ проще, чем вы могли себе представить, просто добавьте префикс go:

go heartbeat()

// keep doing other stuff

Такой подход сравним с инициацией событий в стиле "запусти-и-забудь". Но что, если нам не нужно "забывать", и мы заинтересованы в результате выполнения функции? Именно в этом случае на помощь приходят каналы:

func getName(id int, c chan string) {
    c <- someHeavyOperationToFindTheName(id)
}

func main() {
    c := make(chan string, 2) // выделить канал

    go getName(1, c) // запустить
    go getName(2, c) // запустить снова, не дожидаясь

    // продолжить выполнение других задач

    fmt.Printf("Employees: %s, %s", <-c, <-c) // объединить
}

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

Инструменты


Go был спроектирован, повторюсь, с простотой в уме. Авторы предприняли радикальный подход к решению повседневных действий разработчиков. Попрощайтесь с бесконечными спорами "таб или пробел" и стандартами программирования от групп сообщества, которые пытаются хоть как-то облегчить обмен кодом. Go содержит в себе инструмент go fmt, который берет на себя ответственность за стиль вашего кода. Не нужно больше посылать друг другу файлы конфигураций IDE, не нужно пытаться запомнить, надо ли ставить открывающую скобку на той же строке или следующей.

Документацию библиотеки можно прочитать с помощью go doc, в то время, как go vet поможет найти потенциальные проблемы в коде. Установка сторонник библиотек происходит простой командой go get github.com/[vendor]/[package], а тесты запускаются с помощью go test [package]. Как видите, большинство инструментов, включаемые разработчиками в каждое приложение в каждом языке, уже тут, прямо из коробки.

Развертка


Развертка приложения — необходимое действие и не зависит от языка программирования и того, что пишут с его помощью. Будучи PHP программистом, сколько Capistrano или Envoy конфигураций вы написали за свою профессиональную карьеру? Сколько файлов, измененных вручную, вам приходилось переносить на хостинг-провайдеры во времена FTP?

Вот так выглядит наиболее распространенная и простая развертка PHP приложения:

  • Выгрузить последний код на целевой сервер в новую папку релиза
  • Скопировать закэшированные зависимости и установить измененные
  • Скопировать конфигурационные файлы среды
  • Запустить все скрипты для разогрева приложения
  • Направить ссылку текущего релиза на новую папку релиза
  • Перезапустить PHP-FPM

Некоторые команды используют более продвинутый подход:

  • Выгрузить последний код на сервер создания билдов
  • Создать "билд" (установить зависимости, разогреть кэши, и т.д.)
  • Создать дистрибутивный "артефакт" (архивированный tar.gz файл)
  • Перенести артефакт на целевой сервер
  • Разархивировать в новую папку релиза
  • Направить ссылку текущего релиза на новую папку релиза
  • Перезапустить PHP-FPM

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

А теперь поговорим о процессе развертки Go приложения:

  • Выгрузить последний код на сервер создания билдов
  • Создать билд (заметьте отсутствие кавычек)
  • Перенести артефакт (снова без кавычек) на целевой сервер
  • Перезапустить запущенное приложение

И все. Единственная разница между потенциально простой и продвинутой версией заключается в том, есть ли для этой задачи автономный сервер или нет.

Прелесть в том, что даже не нужно устанавливать Go на целевые сервера, и даже если они работают на разных операционных системах или построены на разных архитектурах процессора, вы, тем не менее, можете подготовить артефакты для них всех (даже для Windows) с одного и того же сервера билдов или любой другой машины.

Вывод


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

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

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

Дополнительные материалы


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

Если этого недостаточно, есть также собрание инициатив сообщества, чтобы помочь отточить полученные навыки.

Если вы любите IDE от JetBrains так же, как и я, стоит посмотреть в сторону плагина Go для IntelliJ, который был создан в основном теми же JetBrains разработчиками. Он может быть установлен почти на любую из их IDE, включая PhpStorm. Для других IDE и текстовых редакторов стоит посетить вики страницу.

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

Менее значимое — это возможность создавать клиентские JavaScript приложения с помощью GopherJS, а также полностью нативные или SDK приложения для iOS и Android.

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


  1. SpyceR
    26.02.2016 21:32
    +1

    Сначала подумал что о Кате..


  1. beduin01
    26.02.2016 22:05
    +7

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

    В этом отношении даже http://nim-lang.org/ куда более удобный, правда когда пишешь на Nim не покидает чувство, что они дергали разные концепции не имея чуткого понимания того, что хотят получить, но когда пытаешься писать на Go создается впечатление, что целью было создать не простой, а именно обрезанный язык.


    1. creker
      26.02.2016 23:00
      +8

      целью было создать не простой, а именно обрезанный язык.

      Благо это быстро проходит. Писать серверный код на Go одно удовольствие


    1. mirrr
      27.02.2016 11:29

      Я видимо что-то делаю не так, ибо ничего не распухает. Но если бы пытался все делать, как привык в php или C++, то наверное так и выходило бы.


    1. uvelichitel
      27.02.2016 15:47

      Зато если удалось "все это завернуть красиво" можно рассчитывать что и работать будет быстрее. Напротив в Haskell, Skala можно быть почти уверенным — чем элегантней код, тем он медленней.


  1. schroeder
    26.02.2016 22:12
    -10

    Да, в статье чего то не хватает… Кати?


  1. stepanp
    26.02.2016 23:20
    +4

    Промт


    1. grossws
      27.02.2016 00:56
      -1

      В обе стороны?


  1. ewgRa
    26.02.2016 23:37
    +8

    Согласен с выводами, но мне кажется тема "с точки зрения PHP программиста" не совсем раскрыта.

    Когда садишься писать на Go после PHP, а особенно Symfony, думаешь о Layers, Abstractions, Interfaces, продумываешь архитектуру и заботишься о том, как этот код будет поддерживаться в дальнейшем, и в большинстве случаев… упираешься в простоту Go и приходиться опять искать другую реализацию архитектуры. В итоге главное принять и поверить — что очевидное и самое простое решение — в Go будет самым правильным, и не надо пытаться вот тут вот сделать интерфейс, а вот тут вот убрать повторение кода, чтобы следовать DRY. Мне показалось что Go диктует простую архитектуру, проблемы поддержки которой решаются именно немонолитностью кода, и после возможностей PHP в плане ООП как решения проблем монолита в это трудно поверить :)

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

    PS. Насчет времени инициализации и т.п., http://symfony.com/blog/new-in-symfony-2-8-symfony-as-a-microframework


    1. SamDark
      27.02.2016 01:13

      Насчет времени инициализации всё равно 11ms. Тут скорее надо давать ссылку на http://reactphp.org/.


      1. Sobit
        27.02.2016 14:57
        +2

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


        1. p4s8x
          27.02.2016 17:33
          +5

          А можете подробнее рассказать о причинах? Есть опыт успешного внедрения у нас в компании, у других пользователей( Fesor точно)
          Разрабатываем backend'ы для мобильных приложений\игр, относительный highload, rpm 200k-500k.

          Помимо ReaсtPHP — есть Icicle, c "coroutines" на генераторах.

          Также есть проект http://amphp.org/ ориентированный на PHP7. Много интересного "из коробки".
          И старый добрый, правда очень монолитный phpDaemon


          1. Sobit
            27.02.2016 18:58
            -4

            На мой взгляд, ReactPHP — это не более, чем попытка доказать, что в PHP можно делать вещи в стиле JavaScript / Node.js. В то время, как 95% всех зависимостей из npm дополняют экосистему Node.js, в PHP это — в точности до наоборот. Редкие фреймворки и библиотеки для PHP спроектированы для асинхронного программирования.

            В конце концов, почему бы просто не использовать Node.js для подобных задач? Взять хотя бы его поддержку сообществом https://github.com/nodejs/node по сравнению с https://github.com/reactphp/react.


            1. ZurgInq
              27.02.2016 19:23
              +6

              У нас ReactPHP успешно работает в продакшене. Да и зачем использовать node.js, если есть %language%


            1. p4s8x
              27.02.2016 20:09
              +5

              На мой взгляд, ReactPHP — это не более, чем попытка доказать, что в PHP можно делать вещи в стиле JavaScript / Node.js.

              А Node.js это попытка доказать, что Javascript подходит для создания сайтов в стиле PHP. На мой взгляд.
              Нет, давайте без вентилятора.

              Редкие фреймворки и библиотеки для PHP спроектированы для асинхронного программирования.

              Любой фреймворк, который представляет абстракцию на Request\Response отлично работает, не знаю, чтобы кто-то щас делал новые фреймворки по-другому, PSR этому способствует.

              Мы используем redis и cassandra — для всего есть async экстеншны. Драйвер для mysql с очень давних времен поддерживает async, лет 5
              Еще можно такой список посмотреть https://github.com/elazar/asynchronous-php


              1. Sobit
                27.02.2016 21:21
                +2

                Хорошая подборка. Спасибо, просветили!


            1. Fesor
              03.03.2016 00:59

              ReactPHP это попытка реализации паттерна "реактор" на PHP, и более чем успешная. И распространения это не получает особо именно из-за консервативных взглядов в духе "php должен умирать".

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

              Основная проблема PHP — отсутствие вменяемой библиотеки асинхронных/неблокируемых функций. Благо проект amphp как раз таки эту проблему рашета, а за счет корутин можно не волноваться по поводу наступления callback hell. Неблокируемый код в синхронном стиле.

              Однако я все же предпочитаю для подобных задач использовать node.js, просто потому что мне лень пилить велосипеды, а для PHP их надо написать еще много (неблокируемых). Есть еще надежда на то что в PHP8 появится async/await. А может и раньше.


    1. MacIn
      27.02.2016 15:24
      +2

      думаешь о Layers, Abstractions, Interfaces, продумываешь архитектуру и заботишься о том, как этот код будет поддерживаться в дальнейшем, и в большинстве случаев… упираешься в простоту Go и приходиться опять искать другую реализацию архитектуры

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

      и не надо пытаться вот тут вот сделать интерфейс, а вот тут вот убрать повторение кода, чтобы следовать DRY

      Потому что иногда это (интерфейсы, ООПизация) становится просто процессом ради процесса.


  1. Skull
    27.02.2016 00:03
    +14

    Теперь давайте вспомним, как мы меняем значения двух переменных в PHP:

    $a = 1;
    $b = 2;
    list($a, $b) = [$b, $a];


    1. mirrr
      27.02.2016 11:38
      -3

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


      1. Elkaz
        27.02.2016 13:38
        +3

        list в PHP это не функция, а языковая конструкция


        1. mirrr
          27.02.2016 13:56

          Согласен, php уже давно не использовал, подзабыл. Но смысла это не отменяет. Автор хотел показать, что в go можно делать так:

          var1, var2, var3 := true, "text", 10

          или так:

          var1, var2, var3 := myFunc()

          Что подставить на второй половине, не имеет значения. Автор использовал для примера смену двух значений. И будь в php коде это list, пример был бы неочевиден.


          1. Borro
            27.02.2016 14:00

            Согласитесь, что это синтаксический сахар. Так же можно найти какой-нибудь сахар в PHP, которого нет в Go


            1. mirrr
              27.02.2016 14:54
              -1

              Прозвучало так, как будто я восхвалял golang. А вы меня осадили.
              Множественное присваивание, как и множественные возвращаемые значения из функций это особенность языка, которую стоило описать в статье. Если будет статья, php глазами гофера, то там стоит упомянуть, что в php такого присваивания нет. Но зато есть что-то другое.


              1. Borro
                27.02.2016 15:31
                +2

                Это сахар, т.к. по факту в PHP тоже можно вернуть несколько значений из функции объединив их в массив, а с помощью list их распаковать. Получается немного больше кода, но копирует 1 в 1 возможность go.


                1. mirrr
                  27.02.2016 15:35

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


                1. creker
                  27.02.2016 17:23

                  Зато эффективность этого кода несравнимая. Не надо сравнивать совершенно разные вещи. Это не просто сахар, а конструкция языка, что позволяет не костыли городить, как вы предлагаете в php, а делать все эффективно и прозрачно.


                  1. Borro
                    27.02.2016 17:28
                    +2

                    list и array конструкции языка PHP, все прозрачно и эффективно.


                    1. creker
                      27.02.2016 17:29
                      +1

                      Это конструкции для массивов, а не для возвращения нескольких значений из функции. Возвращая массив мы возвращаем массив, одно значение, да еще с нехилым оверхедом. Это не прозрачно и не эффективно. Это костыль для решения проблемы, с которой язык не умеет справляться сам.


            1. Sobit
              27.02.2016 15:17
              +1

              Это всего лишь одна из возможностей языка, которая может показаться интересной PHP программисту.


          1. michael_vostrikov
            27.02.2016 16:27
            +2

            Автор хотел показать, что это именно отличие Go от PHP. И в этом он ошибся. Если бы он хотел просто показать множественное присваивание в Go, то про PHP там бы ничего написано не было, так же как в разделах про переменные, циклы и структуры.

            В PHP тоже можно делать так, как вы написали в обоих примерах. По факту отличие только в том, что в Go определена операция "запятая", которая создает… Хм, что же она создает, уж не список ли разнотипных значений, который в PHP называется массивом?

            И что подставить на второй половине значение все-таки имеет. В Go нельзя слева написать 2 переменных, справа 3, в PHP можно.


            1. mirrr
              27.02.2016 16:41
              +1

              Вполне можно

              a, _, b = b, c, a

              И ничего запятая не создает, это просто разделитель между разными переменными.


            1. creker
              27.02.2016 17:19
              +2

              Никаких операций и созданий чего-либо в Go не происходит. Это компилируемый строго типизированный язык. Компилятор знает всю информацию о том, что, какого типа и в каком количестве возвращает функция, что позволяет скомпилировать это без всяких вспомогательных конструкций. У нас уже и так есть стек для этого.

              И таки это совсем не тоже самое, что массивы в PHP.


              1. michael_vostrikov
                27.02.2016 18:06

                Ок, пожалуй, насчет запятой я не прав. Список значений на стеке можно назвать массивом как в C++ или Asm, но не как в PHP.


        1. mirrr
          27.02.2016 16:38

          удалено


          1. Grebenshikov
            27.02.2016 16:40

            Подобно array(), это не функция, а языковая конструкция. list() используется для того, чтобы присвоить списку переменных значения за одну операцию.


            1. mirrr
              27.02.2016 16:54

              Хотя при этом в разделе "Функции PHP > Функции для работы с массивами". Немного сбивает с толку.


    1. Sobit
      27.02.2016 15:15
      +1

      И вас не смущает идея создания массива ради экономии двух строк? К слову.


      1. michael_vostrikov
        27.02.2016 16:37
        -1

        А вас не смущает, что несколько возвращаемых значений сами по себе создают такой массив?) Кстати, не подскажете аналогичную ссылку для Go, как это происходит на низком уровне и сколько памяти занимает?


        1. mirrr
          27.02.2016 16:43

          Нет, не создает. Это просто разные переменные.


        1. creker
          27.02.2016 17:15
          +4

          Можно посмотреть в ассемблере — невероятно, но несколько возвращаемых значений передаются через стек. Никаких массивов там не создается.


      1. Skull
        28.02.2016 17:25
        +1

        Если честно то не очень. Никого же не смущает использование фреймворка с сотнями классов (десятки из которых инстанциируются во время запроса) для простого вывода HTML в браузер.


      1. skobkin
        01.03.2016 18:59
        +1

        Кстати, чисто ради интереса проверил результат на PHP 5.6 и PHP 7.0:

        5.6

        echo memory_get_usage() - $startMemory, ' bytes';
        // 14649168 bytes

        7.0:

        echo memory_get_usage() - $startMemory, ' bytes';
        // 4198640 bytes


        1. Sobit
          01.03.2016 19:37

          Это не сильно меняет суть проблемы.


          1. skobkin
            05.03.2016 04:08

            Есть ещё много простора для оптимизации. Я здесь привёл цифры со словами, что ситуация уже стала лучше.


  1. Arenim
    27.02.2016 00:46
    +8

    Простите за иронию, но...

    Вау, чуваки! Зацените! Тут есть крестообразная отвертка и крест для свершения публичной казни! И то, и другое — крестообразное, так что очень просто перейти от одного к другому!

    Ну ведь правда же "похожий" синтаксис (похожий тем, что и там, и сям есть фигурные скобки и синтаксический сахар) — это мелкая деталь на фоне двух замечательных, но совсем-совсем-совсем разных языков программирования?


    1. mirrr
      27.02.2016 11:40
      +3

      Крестообразной отверткой можно совершать казнь ничуть не хуже.


  1. zim32
    27.02.2016 02:08
    -2

    Как по мне после пхп проще и логичнее всего переходить на джаву, а не на го. Тем более на горизонте котлин.


    1. Rathil
      27.02.2016 02:52
      +5

      Как по мне — не стоит переходить с РНР, а достаточно учить и осваивать новые языки и писать на них. Зачем с чего-то куда-то переходить?
      У нас сейчас проект с миллионом строк кода на РНР, зачем мне переходить на что-то другое, тратить год всей команды, а то и больше, чтобы перейти на что-то другое, которое как-бы лучше? Да и наш шеф то не одобрит такое…
      Я уже молчу о том, что при этом будет +N багов, к уже имеющимся…
      О миграции уже работающих серверах я вообще молчу...


      1. zim32
        27.02.2016 14:32
        +2

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


      1. mirrr
        28.02.2016 14:40
        +1

        На самом деле, большинство багов отсеется на этапе "оно не компилится, ошибка в строке N", так-как компилятор довольно строгий и вероятность скрытых багов гораздо меньше, чем в php или js. В go сами средства языка практически не дают возможности сделать шаг влево-вправо и, я бы сказал, навязывает единый стиль кода и программирования. Я конечно больше сравниваю с nodejs, с которой работаю последние несколько лет. Но и с php тоже знаком не по наслышке.


        1. Rathil
          28.02.2016 15:25

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


          1. mirrr
            28.02.2016 16:05

            Я просто приведу маленький пример. Новичек в php экспериментирует, с таким выражением:

            if ($my_var) { /* .... */ }

            Как поведет себя блок, когда в переменной будет true, 1, "1", "", " ", "string", (10 > "11") и т.д?

            Тот же новичек попробует все подобные варианты в go. Тут он быстро поймет, что скомпилится только первый. Все остальные выдадут ошибку на этапе компиляции. Потому-что go принимает все прямолинейно, только булевы значения. Вот пару примеров, можно нажать и посмотреть ошибки:

            https://play.golang.org/p/t_MDQBvIj1
            https://play.golang.org/p/SCumk_DuV9
            https://play.golang.org/p/DuGHIcdmIq

            Или такой вариант:

            if($test) 
                echo "Ok";
                echo "Test passed!";

            Gо же вообще не позволяет выполнять if, for и т.д. без фигурных скобочек.
            И такой подход практически во всем. Не скажу, что там вообще нет подводных камней, на которые может напороться новичек. Но все гораздо лучше в плане надежности ПО, сужу по реальному опыту применения.


    1. Rathil
      27.02.2016 02:56
      -3

      А о том, что найти специалистов на РНР куда проще, чем на GO, ну в Одессе уж точно.
      Хотя и по РНР сейчас найти опытных не удаётся...


      1. koras_dor
        27.02.2016 14:44
        +1

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


        1. Rathil
          27.02.2016 15:49
          -1

          Да, Вы можете так считать, но я не своё мнение высказал, о озвучил, как оно есть сейчас в Одессе.


          1. Rathil
            28.02.2016 01:02
            +5

            Ну те кто минусуют, если вы из Одессы, рады будем вашему резюме, присылайте и приходите на собеседование.


            1. esc
              28.02.2016 10:37

              Есть простой способ получить неплохого разработчика на Go — берем опытного человека на php и даем ему небольшой проект на Go. Делать он его будет раза в 3 дольше (в первый раз), но в конце уже будет неплохо знать Go.
              Желательно, конечно, чтобы проект для Go подходит лучше, чем для php.

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


              1. Rathil
                28.02.2016 12:13
                +1

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

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


                1. esc
                  28.02.2016 12:19
                  +1

                  Бодишопом веет от такого подхода;)


    1. OnYourLips
      27.02.2016 04:08

      Не вижу смысла переходить с PHP на Java.
      Поделитесь, зачем это нужно.

      Кроме того в рамках класса задач, в которых применяется Go, этот переход точно будет бессмысленным.


      1. PQR
        27.02.2016 13:19
        +1

        А с Java на PHP — как на это смотрите?


        1. Rathil
          27.02.2016 15:52
          +3

          Удивительно, но тот же Ebay, считает, что имеет смысл. Так сейчас они переводят свой раздел по продаже авто в в итальянской версии Ebay с Java на РНР.


          1. PQR
            27.02.2016 20:06
            +1

            Это интересно! Погуглил, но не нашел эту историю. У Вас есть ссылка?


            1. Rathil
              28.02.2016 01:00

              Нет, ссылки нет. Знаю от друга, к ним, в крупную фирму, зашёл этот проект, вот он и делился информацией.


        1. SamDark
          28.02.2016 01:28

          Я перебрался. Для веба J2EE в 2006--2008 был тяжеловат в плане количества телодвижений.


      1. zim32
        27.02.2016 14:54
        -3

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


        1. andrewnester
          27.02.2016 15:20
          +3

          обожаю ничем необоснованные суждения


          1. zim32
            27.02.2016 15:51
            +2

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

            1) В хайлоаде пхп проигрывает… да уже почти всем. nodejs, java, erlang, даже питон со своим GIL и то выигрывает
            2) Ентерпрайз — java, с#
            3) Обработка больших данных — java (привет хадуп), R, python
            4) Алгоритмы искусственного обучения — опять таки java, python, c++
            5) Разработка мобильных приложений — java (андроид), objective-c, swift (ios), ну и с трудом С++ (привет QT)
            6) Десктоп — ну там все понятно
            7) Микросервисы — опять java, привет GO (о чем статья), node возможно еще что-то. Тут еще пхп может посоперничать (если нагрузка не велика)


          1. myrrec
            27.02.2016 16:22
            +2

            А сарказм?


  1. SirEdvin
    27.02.2016 03:56
    -5

    Статья не так уж и плоха, но ...

    А теперь поговорим о процессе развертки Go приложения:

    А как же магия GOPATH? Даже тот же PHP скачал, поставил, запустил — работает. А в go нужно настраивать GOPATH :(


    1. creker
      27.02.2016 12:31

      Серьезно? Подход Go как раз в том, что на GOPATH все и ограничивается. Дальше все просто работает, одной командой в консоли. Редкий компилируемый язык так может.


    1. mirrr
      27.02.2016 13:19
      +7

      Ничего себе, нужно иметь научную степень, наверное, чтобы прописать переменную окружения.


    1. koras_dor
      27.02.2016 14:47

      А как же локальный вэб-сервер поднимать, что бы заработал php? Я думаю это совокупно GOPATH.


      1. Rathil
        27.02.2016 16:26
        +2

        Ну пишите без него, биндите порт и вперёд, но ЗАЧЕМ?



  1. lumini
    27.02.2016 07:30
    +2

    Нубский вопрос про деплой Go веб-приложения на Windows. Начал изучать язык, собрал exe простейшего приложения на Gin, залил его на виндовс сервер, через рдп запустил, на IIS настроил reverse proxy на порт приложения. Все вроде бы хорошо, но хочу залить обновление, а процесс приложения не дает перезаписать exe через ftp. Есть ли какие-то общепринятые методы деплоя, желательно без ручного вмешательства в остановку-запуск приложения. И существует ли что-то вроде Node.js-ного Forever, рестартующего веб-апп в случае вылетания по эксепшну?


  1. ZurgInq
    27.02.2016 10:47
    +6

    Каждый PHP разработчик знает, что, если ему удасться довести время инициализации большого монолитного приложения до 30мс, это отличный результат! Добавить к этому 50-100мс для обработки самого запроса, и перед нами поразительное общее время ответа.

    Symfony2, nginx+php-fpm, простой запрос — время ответа 20-30мс. И это на тяжёлом фрэймворке с кучей зависимостей и библиотек.
    Golang, библиотека gin, CRUD на БД, время ответа от без нагрузки на БД — 1-10мс. Разница существенна. Но не критична. Если на php убрать обвязку из Symfony, то разница ещё больше сократится.

    Развертка приложения — необходимое действие и не зависит от языка программирования и того, что пишут с его помощью. Будучи PHP программистом, сколько Capistrano или Envoy конфигураций вы написали за свою профессиональную карьеру? Сколько файлов, измененных вручную, вам приходилось переносить на хостинг-провайдеры во времена FTP?

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

    Складывается впечатление, что автор не знаком с php. Бесспорно, golang эффективнее чем php для написания микросервисов, но статья вводит в заблуждения относительно не эффективности php.
    Сейчас в своей работе я использую связку ruby + golang. На обоих языках написано несколько "микросервисов". Основное выявленное преимущество Go — более низкое потребление памяти и боле эффективная работа с внешними асинхронными запросами.


    1. PQR
      27.02.2016 13:25

      В разделе про публикацию PHP приложений последним пунктом идёт "Перезапустить PHP-FPM" — зачем? Выкладываем новые исходники и они просто работают! Причём текущие запросы не будут сброшены. А с go приложением, получается, при перезапуске процесса мы можем потерять запросы которые были где-то в середине процесса обработки! Или есть способ zero-downtime перезапуска go приложения?


      1. Borro
        27.02.2016 13:33
        +2

        Можно же перезапуск устроить так, что он не будет отстреливать всё, а дожидаться завершения последнего запроса. Как nginx c reload


        1. SamDark
          28.02.2016 01:31

          Можно, только graceful shutdown писать руками придётся...


      1. ImLiar
        27.02.2016 13:39
        +1

        Graceful shutdown + load balancer + несколько инстансов приложения, обновляемых по очереди. Вот вам и zero downtime.

        Это нормальная практика для всех приложений, будь то go, python, java и прочее, что висит как процесс


        1. SamDark
          28.02.2016 01:31

          Руками придётся писать же, не?


          1. ImLiar
            28.02.2016 02:31

            Все зависит от того, что используете. В finagle на scala есть graceful shutdown из коробки. Наверняка есть готовые решения для множества платформ


            1. SamDark
              28.02.2016 15:00

              Для Go не было.


              1. mirrr
                28.02.2016 15:31

                Из коробки нет, но есть множество пакетов, типа https://github.com/facebookgo/grace


                1. SamDark
                  29.02.2016 01:10

                  Рекомендуете именно этот?


                  1. mirrr
                    29.02.2016 03:43

                    Порекомендовать не могу, так-как сам не использую.
                    Вообще, есть еще варианты, например простой пакет https://github.com/tj/go-gracefully от авторов известного фреймворка express для nodejs


      1. Sobit
        27.02.2016 15:56
        +2

        При наличии OPcache или APC, новые изменения не будут "просто работать".

        $ php5-fpm reload

        Команда очистит кэш и принудит его пересоздание при первом обращении.

        В случае Go приложения, если есть несколько образцов приложения, проблем возникнуть не должно (как пояснил ImLiar). С одним же образцом можно запустить новую версию на соседний порт, перенаправить запросы с веб-сервера на него, и отключить старый после короткого ожидания.


        1. SamDark
          28.02.2016 01:32

          Не будут работать только если время жизни кеша бесконечно. И даже в этом случае перезапускать не обязательно. Что APC что OpCache можно вычистить без перезапуска.


          1. zerkms
            28.02.2016 12:23

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


            1. SamDark
              28.02.2016 15:01

              Может и создаёт, да.


    1. mirrr
      27.02.2016 13:31

      Не могу согласиться, что только в памяти дело. У меня зачастую время ответа скрипта на golang — микросекунды, миллисекунды — при сколько-либо существенной нагрузке.

      Синтетика конечно, но все же
      image


    1. Sobit
      27.02.2016 15:38
      +1

      Если время ответа CRUD сервиса на Go составляет 10мс, я бы занялся поиском причин.

      Далее приводиться огромный список шагов, который не отражает действительность. Первичная настройка капистрано — 5 минут. Деплой — одна консольная команда.

      А разве то, что делает эта консольная команда, — не тот же самый "огромный список шагов"?


      1. ZurgInq
        27.02.2016 19:16
        +1

        Если время ответа CRUD сервиса на Go составляет 10мс, я бы занялся поиском причин.

        Причина — время ответа от БД, и тут без разницы, golang, php, python, ruby. На php время ответа будет в пределах 50мс, что конкретно в моём случае не критично.

        А разве то, что делает эта консольная команда, — не тот же самый «огромный список шагов»?

        Тот же самый. Там может быть хоть 100 шагов. Можно и golang приложение каждый раз компилировать, переносить на сервер и вручную перезапускать. А можно воспользоваться готовыми инструментами, которые всё сделают сами. И под php\python\ruby эти инструменты сейчас заточены гораздо лучше.


        1. SamDark
          28.02.2016 01:35

          В PHP (классическом с умиранием) соединение с БД делается каждый раз, если не используется persistent connect (в котором много подводных камней). В Go соединение делается один раз и далее повторно используется.


          1. mirrr
            28.02.2016 14:50

            И при этом в Go значительно проще организовать кеширование, фильтр Блума, hyperLogLog и многие другие вещи, которые помогают вообще не делать запросы в базу при каждом обращении.


            1. SamDark
              28.02.2016 15:02

              Факт. С другой стороны, при наличии нескольких инстансов фронта это всё усложняет приложение неимоверно, хоть и даёт отличную производительность.


              1. mirrr
                28.02.2016 16:15

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


          1. creker
            28.02.2016 17:56

            Даже все хитрее. В Go sql.DB это не соединение, а пул, который сам создает, переиспользует и убивает соединения до базы.


          1. Fesor
            03.03.2016 01:10

            в котором много подводных камней

            На самом деле эти "подводные камни" заключаются лишь в том, что бы люди убирали за собой, а не надеялись что PHP волшебным образом отменит незавершенные транзакции и т.д. Ну то есть та же проблема, по которой понадобились сборщики мусора, или та проблема, из-за которой среднему php-нику нельзя давать работать с тредами или "не умирающим пыхом". Возьмут ребята какой-нибудь react/amphp, впихнут туда доктрину синхронную, и потом кричат направа налево, что PHP не подходит для реализации эффективных решений.

            Реализовать небольшую оберточку поверх PHP, которая по завершению запроса будет "невилировать" сайд эффекты текущего запроса, это как бы не сложно.


            1. SamDark
              03.03.2016 15:21

              Это не "лишь". Это серьёзно :)


  1. forth
    27.02.2016 18:33
    +4

    Многие компании, такие как Facebook, Yahoo!, Wikipedia, Wordpress, Tumblr, начинали свою историю с PHP

    Yahoo! в этом списке вероятно по ошибке. Yahoo! на несколько лет старше, чем PHP.


  1. beduin01
    27.02.2016 18:46

    «Многие компании, такие как Facebook, Yahoo!, Wikipedia, Wordpress, Tumblr, начинали свою историю с PHP»
    Альтернатив просто не было. А те что были были еще хуже.


    1. SamDark
      28.02.2016 01:36
      +1

      Да ладно, Java уже была...


      1. AstRonin
        02.03.2016 08:52
        -2

        Java хуже параллелится...


        1. grossws
          02.03.2016 11:27

          Иногда лучше молчать… У явы очень разумное concurrency и качественная memory model (jmm, собственно).


          1. AstRonin
            02.03.2016 13:49

            Иногда лучше молчать…

            Это верно.
            О чем я говорю, и о чем вы, вообще не в тему...


        1. SamDark
          02.03.2016 14:43

          Не хуже, но немного сложнее.


  1. RomanPyr
    27.02.2016 18:56
    +2

    замечательные черты, как легкий параллелизм

    вы должны знать две вещи о параллельности в Go — горутины и каналы.

    Горутина имеет простую модель: это функция, выполняемая параллельно с другими горутинами в едином адресном пространстве.

    Чувак ни фига не понял.


    1. Sobit
      27.02.2016 19:04

      Честное замечание. Я пытался найти более подходящий перевод для "concurrency". Обновлю статью, если посоветуете.


      1. RomanPyr
        27.02.2016 19:34

        Так это перевод такой? Я думал в оригинале parallelism.
        Конкурентность.


        1. ivaaaan
          27.02.2016 20:26
          +1

          перевод с его собственного блога. можно ли назвать переводом..? =)


          1. Sobit
            27.02.2016 21:08
            +1

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


      1. Randl
        27.02.2016 22:30

        Одновременность?


  1. enakenenaken
    28.02.2016 10:19
    -2

    Интересные и удобные конструкции, но новичкам лучше с него на начинать. Иначе новички не поймут, что собственно упрощалось и объединялось, и почему можно по другому.


  1. komiller
    29.02.2016 08:53
    -5

    Перевод нормальный ребята, прочитал понял суть вроде не Перельман :) Собит молодчик хорошая статья. Привет из 2шанбе :)


  1. rudevich
    01.03.2016 11:51
    +1

    Друзья, поясните пожалуйста, а что произойдет, если someHeavyOperationToFindTheName не успеет заполнить "c" до момента ее использования? Как понять заполнила ли она "c" или нет? Есть событие?


    1. mibori
      01.03.2016 13:00
      +2

      Строчка fmt.Printf("Employees: %s, %s", <-c, <-c)

      сначала будет вычислять аргументы в таком порядке: "Employees: %s, %s", <-c, <-c. То есть для вывода на экран значений она сначала вытащит два значения из канала. Если в канале значений нет, то "<-" будет ждать их появления.

      чтобы не ждать, можно делать, например, так:

      select {
      case str := <-c:
           // значение было в канале и мы его вытащили в str
      default:
           // канал еще пуст
      }


      1. rudevich
        01.03.2016 13:06

        Спасибо! Какой забавный язык :)


      1. WaveCut
        01.03.2016 17:04

        Был тот же вопрос, спасибо за ответ!