Перевод: Один год с Go

http://vagabond.github.io/rants/2015/06/05/a-year-with-go/
  • Перевод
Под катом — перевод статьи опытного разработчика о его опыте практического применения Go. Важно — мнение переводчика может не совпадать с мнением автора статьи.




Итак, прошел год с тех пор, как я начал использовать Go. Неделю назад я удалил его из production.

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

Итак, поговорим о том, почему я не считаю Go полезным инструментом:

Инструментарий


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

анализ покрытия


Строго говоря, утилита для анализа покрытия кода в Go — это хак. Она работает только с одним файлом за раз и делает это, вставляя в него примерно вот такой код:

GoCover.Count[n] = 1

Где n — это идентификатор позиции ветвления в файле. Ну а еще она вставляет в конец файла вот такую гигантскую структуру:

действительно гигантская
var GoCover = struct {
        Count     [7]uint32
        Pos       [3 * 7]uint32
        NumStmt   [7]uint16
} {
        Pos: [3 * 7]uint32{
                3, 4, 0xc0019, // [0]
                16, 16, 0x160005, // [1]
                5, 6, 0x1a0005, // [2]
                7, 8, 0x160005, // [3]
                9, 10, 0x170005, // [4]
                11, 12, 0x150005, // [5]
                13, 14, 0x160005, // [6]
        },
        NumStmt: [7]uint16{
                1, // 0
                1, // 1
                1, // 2
                1, // 3
                1, // 4
                1, // 5
                1, // 6
        },
}


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

анализ производительности


То же самое с утилитой для анализа производительности — выглядит хорошо, пока не посмотришь как она работает. А работает она путем оборачивания кода в цикл с переменным количеством итераций. После чего цикл итерируется пока код не выполняется «достаточно долго» (по умолчанию 1 секунда), после чего общее время выполнения делится на количество итераций. Такой подход не только включает в замер производительности сам цикл, но также скрывает флюктуации. Код реализации из benchmark.go:

func (b *B) nsPerOp() int64 {
    if b.N <= 0 {
        return 0
    }
    return b.duration.Nanoseconds() / int64(b.N)
}

Эта реализация замаскирует паузы сборщика мусора, замедление связанное с гонками выделения ресурсов и другие интересные вещи, если они случаются не слишком часто.

компилятор и go vet


Одна из обсуждаемых сильных сторон Go — это быстрая компиляция. Насколько я могу сказать, это частично достигается за счет того, что многие проверки, которые обычно делает компилятор просто пропускаются — они реализованы в go vet. Компилятор не проверяет проблемы с одинаковыми именами переменных в разных областях видимости или с некорректным форматом printf, все эти проверки реализованы в go vet. Более того, качество проверок ухудшается в новых версиях: в версии 1.3 не показывает проблемы, которые показывала версия 1.2.

go get


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

$GOPATH


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

Go race detector


Вот это — неплохая штука. Огорчает что оно вообще нужно. Ну и тот факт, что работает не на всех поддерживаемых платформах (FreeBSD, кто-нибудь?) и максимальное количество goroutine всего 8192. Более того, необходимо умудриться столкнуться с race condition — что довольно трудно, учитывая насколько race detector все замедляет.

Рантайм


Channels/mutexes


Каналы и мьютексы МЕДЛЕННЫЕ. Добавление синхронизации через мьютексы на production настолько снизило скорость работы, что лучшим решением стал запуск процесса под daemontools и его перезапуск в случае падения.

логи падений


Когда go падает, все без исключения goroutine отгружают свой стек вызова в stdout. Объем этой информации растет с ростом вашей программы. Более того, многие сообщения об ошибках косноязычно сформулированы, к примеру ‘evacuation not done in time’ или ‘freelist empty’. Создается впечатление что авторы этих сообщений задались целью максимизировать трафик к поисковому движку google, потому что в большинстве случаев это единственный способ понять что происходит.

интроспекция runtime



Не работает, на практике Go поддерживает в живых концепцию «отладка принтами». Можно использовать gdb, но не думаю что вы захотите это делать.

Язык


Я не получаю удовольствия от написания кода на Go. Я либо сражаюсь с ограниченной системой типов с кастами всего в interface{} либо занимаюсь копипастой кода который делает практически одно и то же для разных типов. Каждый раз, когда я добавляю новую функциональность это выливается в определение еще большего количества типов и допиливания кода для работы с ними. Чем это лучше использования C с адекватными указателями, или использования функционального кода со сложными типами?

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

Проблемы вызывает преобразование byte[] в string и работа с массивами/слайсами. Да, я понимаю для чего все это было сделано, но по моим ощущениям оно слишком низкоуровневое по отношению к остальному языку.

А еще есть [:],... с append. Посмотрите на это:

iv = append(iv, truncatedIv[:]...)

Этот код требует ручного контроля, потому что append в зависимости от размера массива либо добавит значения, либо сделает перевыделение памяти и вернет новый указатель. Здравствуй, старый добрый realloc.

стандартная библиотека


Часть стандартной библиотеки неплоха, особенно криптография, которая в лучшую сторону отличается от простой обертки над OpenSSL, которую вам предлагает большинство языков. Но документация и все что связано с интерфейсами… Мне часто приходится читать код реализации вместо документации, потому что последняя часто ограничивается бесполезным «имплементирует метод X».

Большие проблемы вызывает библиотека 'net'. В отличие от обычных сетевых библиотек, эта библиотека не позволяет менять параметры создаваемых сокетов. Хотите установить флаг IP_RECVPKTINFO? Используйте библиотеку 'syscall', которая является самой плохой оберткой над POSIX из всех, которые я видел. Нельзя даже получить файловый дескриптор созданного соединения, все приходится делать через 'syscall':

Скрытый текст
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_DGRAM, 0)
if err != nil {
    rlog.Fatal("failed to create socket", err.Error())
}
rlog.Debug("socket fd is %d\n", fd)

err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1)
if err != nil {
    rlog.Fatal("unable to set IPV6_RECVPKTINFO", err.Error())
}

err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
if err != nil {
    rlog.Fatal("unable to set IPV6_V6ONLY", err.Error())
}

addr := new(syscall.SockaddrInet6)
addr.Port = UDPPort

rlog.Notice("UDP listen port is %d", addr.Port)

err = syscall.Bind(fd, addr)
if err != nil {
    rlog.Fatal("bind error ", err.Error())
}


А еще вы получите море удовольствия, получая и передавая byte[] при вызове 'syscall' функций. Создание и удаление C структур из Go — это просто какой-то заряд позитива.

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

Выводы


Я не могу понять смысл Go. Если мне нужен системный язык, я использую C/D/Rust. Если мне нужен язык с хорошей поддержкой параллелизма, то я использую Erlang или Haskell. Единственное применение Go, которое я вижу — это утилиты командной строки, которые должны быть портабельны и не тянуть за собой зависимости. Я не думаю, что язык хорошо подходит для «долгоживущих» серверных задач. Возможно, он выглядит привлекательно для Ruby/Python/Java разработчиков, откуда, насколько я понимаю, и пришло большинство разработчиков на Go. Я также не исключаю, что Go станет «новой Java», учитывая легкость развертывания и репутацию языка. Если вы ищите более хорошую версию Ruby/Python/Java, возможно, Go вам подойдет — но я бы не рекомендовал останавливать свой поиск на этом языке. Хорошие языки программирования позволяют вам развиваться как программисту. LISP демонстрирует идею «код как данные», «C» обучает работе с компьютером на низком уровне, Ruby показывает работу с сообщениями и анонимными функциями, Erlang рассказывает про параллелизм и отказоустойчивость, Haskell демонстрирует настоящую систему типов и работу без побочных эффектов, Rust позволяет понять как разделять память для параллельно выполняемого кода. Но я не могу сказать, что научился чему-то, используя Go.
Метки:
Поделиться публикацией
Комментарии 304
  • +4
    Ну а мнение уважаемого переводчика каково?
    • +18
      Я не переводчик, добавлю от себя.

      Попробовал писать на Go несколько домашних поделок, на работе пишу на C#. Если вкратце, я пока так и не смог оценить преимуществ Go, кроме кросплатформенности:

      1. Нет удобных средств для разработчика, IDE со встроенным дебаггером под винду так и не нашёл. Пользуюсь плагином для Idea
      2. Каналы — удобно, но мне они нужны для параллельной обработки массивов данных. В C# это решается проще, Parallel.ForEach и вперёд
      3. Очень непривычно создавать свои ненужные структуры для простой сортировки в Go. И в целом, LINQ для работы с коллекциями в разы удобнее. При работе с Go сильно не хватает
      4. Зачастую, Go кажется слишком низкоуровневым, даже чрезмерно. В идеале, не хотел бы видеть в языке указатели без особой на то причины
      5. Использовал библиотеку написанную на C++ в Go. Не скажу, что очень удобно, а, например, valgrind и вовсе не работает с такими приложениями. Встроенный отладчик память, выделенную в C++ коде, разумеется, не видит. И как отлаживать утечки?


      В целом, язык интересный, но для себя достоинств я пока не увидел.
      • +6
        Аналогично, в основном на работе пишу на C#, тогда как хобби C++\Qt\QML. И те же самые замечания! К LINQ очень быстро привыкаешь, к генерикам, к честным ссылкам, к нормальной работе со строками в конце концов (А то в Go это то ли функции из «bytes», то ли «strings», и непонятно, выстрелит ли это в плане локализации)! Хотя некоторые вещи вроде «go» и «defer» хороши.
        • 0
          Dim0FF, QtRoS go-linq пробовали?
          • 0
             From(students).
             Where(func (s T) (bool, error){
                        return s.(*Student).age >= 20, nil
                }).
            


            Я правильно понимаю, что (а) внутри Where используется делегат и (б) в этом делегате входной параметр приводится к нужному типу?
            • 0
              Import your []*Student.
              Find those over 20. Note T is an alias for interface{}. So we make type assertion to our input type.

              Да.
              • 0
                Мда. Боль и печаль.
                • 0
                  Dim0FF RomanPyr lair Ну есть менее печальные варианты , хотя далеко и не идеальные.
                  • 0
                    Все равно же делегаты, да?
                    • 0
                      Нет — в gen используются конкретные типы, поэтому приводить ничего не нужно.
                      • 0
                        Я не спрашивал, есть ли приведение типов (я вижу, что нет), я говорю, что аргумент Where — делегат. Это ведь так?
                        • 0
                          А — является ли аргумент Where функтором(лямбдой, замыканием, функциональным обьектом — как хотите) — да является. Честно говоря сложно представить реализацию без функтора.
                          • 0
                            • +1
                              Либо я чего-то не понимаю в C#, либо в
                              fruits.AsQueryable().Where(fruit => fruit.Length < 6);
                              


                              fruit => fruit.Length < 6
                              


                              Как раз та самая лямбда-функтор-предикат.
                              • 0
                                Зависит от того, что именно вы понимаете под лямбдой/функтором.

                                fruits.AsEnumerable().Where(fruit => fruit.Length < 6);
                                


                                Внутри Where — делегат (анонимная функция), которая будет скомпилирована в исполняемый код вместе со всем остальным кодом вокруг, и выполнена .net-рантаймом в момент итерации.

                                fruits.AsQueryable().Where(fruit => fruit.Length < 6);
                                


                                Внутри Whereвыражение (AST), которое в момент компиляции будет только построено, а вот в рантайме будет проанализировано и выполнено тем способом, который нужен провайдеру, лежащему под fruits. Например, преобразовано в предикат WHERE Length < 6, если провайдер поверх БД. Или в $filter=Length lt 6, если провайдер поверх OData.
                                • 0
                                  Черная магия .Net (:

                                  Не знал про такое — но это свидетельствует скорее о умном компиляторе IL кода, нежели выразительности самого языка. Такие вот «макросы времени исполнения», причем подобная «магия» в коде далеко не всегда оправдана. Честно говоря после войн с Hibernate в яве, я очень осторожно отношусь к «умным выражениям». Да и AOT накладывает ограничения на такие вещи.

                                  Впрочем формально, это действительно вполне обычный предикат-функтор.

                                  П.С. На C# и .Net действительно очень много вкусных и интересных вещей. Но есть и проблемы — эталонная реализация работает только под Windows, поэтому если у вас Linux\*BSD то продвинуть использование шарпа нетривиально. Вторая этот тот факт, что даже если вам удалось продвинуть Mono — ваша реализация будет медленнее работать и может быть подвержена ошибка среды исполнения (тут был цикл статей о нем). Ну и наконец третье, что экосистема шарпа скуднее по сравнению с той же явой.
                                  Во вторых, Go и C# уж совсем разные сегменты рынка занимают. Откуда такой интерес?
                                  • 0
                                    Не знал про такое — но это свидетельствует скорее о умном компиляторе IL кода, нежели выразительности самого языка.

                                    Ну, как… Есть у меня самописный недоORM-фреймворк для плюсов, там тоже можно писать вещи типа (простите за куски кутей)
                                    struct Record
                                    {
                                        int m_id;
                                        QDateTime m_timestamp;
                                        QString m_name;
                                    };
                                    // ...
                                    Adapted<Record> queries;
                                    auto records = queries.SelectByFields (_1 <= yesterdayDate && _2 == thisName);
                                    

                                    Разворачивается тоже в какое-то там SQL-выражение, в точке SelectByFields проверяются типы (чтобы ненароком не было выражения со сравнением даты со строкой или int'ом), в рантайме никаких лямбд нет, и так далее.

                                    Адресация, к сожалению, позициональная, именованную с достаточно кратким синтаксисом (чтобы не писать &Record::m_timestamp <= yesterdayDate) я пока не придумал.

                                    ДженерикиТемплейты для реализации всего этого пригодились, да.

                                    Ну это так, к выразительности языка.
                                    • 0
                                      Как раз здесь уже не провайдер, а полноценная решение на метапрограммировании шаблонами. Т.е. в данном случае не конечная реализация подстраивается под код, а работает условная «генерация» реализации из требований.
                                      • 0
                                        Однако же, язык позволяет это выразить. И про это-то и речь!
                                        • 0
                                          В выразительности плюсов никто никогда не сомневался. Вопрос в отладке таких шаблонов (концепты привет) и времени компиляции этого дела.

                                          Из этого кода Boost Spirit вспомнился.
                                          • 0
                                            Компилируется, гм, небыстро, да. Но и с этим можно бороться. Да и отладка достаточно проста, если напихать static_assert'ы в нужных местах. Конечно, концепты эти ассерты заменят. Потому и жду.

                                            Что печальнее — бинари серьёзно раздуваются в дебаг-билдах (и, как следствие, пострипанная debug-информация и dbg-пакеты во всяких там линуксах).

                                            Спирит прекрасен, конечно. Хаскелевский parsec/attoparsec-код можно переносить практически не думая.
                                    • 0
                                      Не знал про такое — но это свидетельствует скорее о умном компиляторе IL кода, нежели выразительности самого языка.

                                      Не, IL-компилятор здесь вообще ни при чем. Это чисто C#-ный трюк, когда стрелочная запись в зависимости от ожидаемого типа разворачивается либо в анонимный метод, либо в конструктор AST (очень грубо — в LambdaExpression(CompareExpresssion(MemberAccessExpression(ParameterExpression("fruit"),"Length"), LessThan, ConstExpression(6)))). А дальше это AST уже разворачивается исполняемым кодом.

                                      Это не макрос, это совсем другого рода развлечение, очень мощное, по-своему.
              • 0
                Спасибо, попробую.
                • +1
                  Не, ну это как раз-таки та вещь, которую тут почти единогласно осуждают — использовать привычные для одного языка подходы в другом, где они совсем «неродные».
            • +3
              Вот смотрите, вы же в C# понимаете отличия struct от object? Где они располагаются, как передаются в качестве параметра? Также, думаю, вам вполне понятны значения модификаторов ref и out? А давайте добавим сюда еще unmanaged код, где можно проводить операции с указателями, stackallock и fixed. Получается что в C# тоже не все просто. Кому-то тоже это может не нравится, а кто-то настолько привык, что даже не замечает. Видимо дело в привычке.
              • +2
                Каналы — удобно, но мне они нужны для параллельной обработки массивов данных. В C# это решается проще, Parallel.ForEach и вперёд

                Каналы вместе с горутинами по-идее призваны избавиться от callback-hell, который присутствует в некоторых языках.
                • 0
                  В C# от него защищают async/await, если я все правильно понимаю.
                  • +1
                    На C# не пишу, почитал сейчас немного про acyns/await. Насколько успел разобраться, это все же разные подходы.
                    Го меня цепляет тем, что можно просто писать plain-код. Тот же async/await будет работать не с любой функцией, она должна это поддерживать, а в го можно любое действие дернуть через go… и оно не будет блокировать остальные потоки выполнения. Т.е., тут не асинхронная модель.
                    В совокупности с каналами и особенно с такой фичей как «select» это позволяет очень легко писать сложную логику управления кучей параллельных задач. Но за это мы платим тем, что нужно следить за потокобезопасностью кода, в го у нас нет гарантий, что в середине функции планировщик не переключится на выполнение другой функции.
                    • +1
                      Есть.
                      «Планировщик, я закончил на пока, дай другим поработать в моей треде» горутина говорит либо явно (есть спец функция), либо делая блокирующую операцию (чтение из канала). Примечательно, что если совершается системный вызов, то горутина зависает вместе со всей тредой и планировщик вынужден либо ждать, либо родить еще одну треду. Такие пироги.
                      Очевидно, что рядом работают в других тредах другие горутины и они могут начать писать туда, куда пишем мы. Но единственный язык, где об этом не нужно думать, это Rust.
                      • +1
                        > единственный язык, где об этом не нужно думать, это Rust.
                        Ну почему же. Есть Erlang, Haskell, Clojure, где об этом точно не надо думать.

                        А рантайм Erlang-а, например, достаточно умен, чтобы выполнять блокирующие системные вызовы на отдельном пуле тредов, что делает работу системы еще более предсказуемой.
                        • +1
                          Дак вот как раз если горутина слишком долго тупит (это может быть и не системный вызов), то создается еще тред, в который запихиваются другие горутины. Вот тогда мы и получаем возможные проблемы с одновременной записью в map, например, если не учтем этого.
                          Вот довольно тупой пример, иллюстрирующий ситуацию. pastebin.com/jkH1Nvp2
                          $ go run check.go
                          Count 10000; 25.437204715 - 25.484347422
                          Count 20000; 25.437177393 - 25.605745478
                          End
                          

                          Как видим, горутины тут пересекаются по времени выполнения, хотя никаких блокирующих операций не делается.
                          • 0
                            В Go 1.5 GOMAXPROCS по дефолту ставится равным числу ядер, соответственно, горутины выполняются на нескольких тредах по умолчанию.
                            То есть, ваш пример не демонстрирует ничего, кроме стандартного поведения.
                            • 0
                              Я и хотел показать стандартное поведение, что у нас нет гарантии того, что в середину одной горутины не может врезаться другая, например в середине записи в map попытаться тоже получить доступ к этому мапу. Если мы об этом не позаботились.
                              • 0
                                А, ну ок, я не тот мессидж прочитал.

                                BTW, в корректности вот этого тезиса

                                > если горутина слишком долго тупит
                                > (это может быть и не системный вызов), то
                                > создается еще тред, в который запихиваются другие горутины

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

                              > Вот тогда мы и получаем возможные проблемы с одновременной записью в map, например, если не учтем этого.
                              Я просто не представляю, как можно не учесть этого. Невнимательность? Да, но а как же иначе? Если язык будет это за нас учитывать (не методами разделения ресурсов аля Rust, а блокировками) то мы, возможно, получим потери в скорости, где нам бы этого не хотелось.
                              • 0
                                Да, я некорректно выразился насчет остановки. Но технически такое может произойти если два треда попадут на одно ядро. Их будет переключать планировщик ОС.
                                • 0
                                  Да, это конечно так :)
                  • 0
                    Я считаю, что синтаксис и текущая реализация языка программирования — вторичны по отношению к экосистеме и сообществу. Где был javascript? А потом пришли ребята с V8, другие ребята с node.js — и все поменялось в течении пары лет. В дизайне самого языка есть спорные момент: GOROOT, отказ от классов, ручное управление контейнерами, контроль ошибок через возвращаемые значения — но все это сделано с определенными целями — серверная разработка «чтобы не текло и не падало». У меня нет большого практического опыта работы с Go. Что видел — работает быстро, но программисты жалуются что много ручной работы на низком уровне. Время покажет куда он будет развиваться и какое вокруг него сформируется сообщество.
                    • +13
                      Не согласен со вторичностью. У разработчиков экосистемы должна быть мотивация её развивать. Чтобы написать node.js надо угорать по языку и мечтать засунуть его всюду.
                      • +3
                        Тут, по-моему, не угадаешь. Как показывает практика, небольшая группа энтузиастов может угорать по чему угодно, сообщество формируются слабо прогнозируемым способом.
                      • +12
                        а чего поменялось то? Как была лапша с коллбеками и промисами, так она там же и осталась
                        • 0
                          В том-то и магия. Ничего по сути не поменялось — а популярность растет. И разработчики думают над способами борьбы с лапшой. Генераторы и async await вот сделали :)
                          • +2
                            На самом деле, тут все достаточно просто объяснимо, по крайней мере, постфактум.
                            1. Случайно образовался JS в браузере. Пусть достаточно случайное явление, но язык не повернется назвать магическим.
                            2. Жесткая конкуренция за растущий пирог случайно привела к тому, что он оказался во всех современных браузерах. Вот это магия, на мой взгляд. Условия рынка сложились достаточно специфические, здесь было вариантов пока еще много. Дальше все строго предсказуемо.
                            3. Пирог веба вырос настолько, что браузеры стали использоваться почти всеми цивилизованными людьми чуть ли не каждый день. Оно и понятно: почти мгновенная коммуникация — лучшее изобретение человечества пока что.

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

                            Итак, JS везде и не содержит изъянов, делающих его использование невозможным. Чего ждать? Того, что мы сейчас имеем. Пока веб-платформа не упрется в свои фатальные недостатки, она будет расти в сторону еще большего распространения, улучшения скорости работы и развития инструментов разработки. В принципе, после анонса WASM у меня не хватает фантазии, что еще может выйти определяющего.
                            Разве что расширение набора инструкций ARM для более эффективной работы виртуальной машины JS, но сначала надо стандартизировать их как следует.

                            Так что, думаю, популярность растет просто потому что до сих пор не уперлась в потолок, но не просто так, а потому что JS-интерпретатор — самый распространенный на планете интерпретатор/компилятор.
                        • +3
                          Для javascript особо альтернативы не было по-моему. И, увы, никто так и не создал адекватной альтернативы (а еще — лучше замены связки HTML+JS+CSS) и теперь приходится с этим жить.
                      • +4
                        Хороший перевод. Но я еще ожидал немного Вашего мнения по теме, ибо его несоответствие с мнением автора особенно выделено перед переводом.
                        • +39
                          Это дисклеймер, чтобы фанаты Go не слили переводчику карму.
                          • +10
                            В целом да :). На Хабре не все читатели замечают что какая-то статья является переводом и начинает обращаться к переводчику как к автору. А у переводчика нет года практического опыта работы с Go
                        • +8
                          Еще одна мелочь в Go, которая меня дико раздражает, — это отсутствие optional arguments. Ну ничего, подумал я, можно ведь выкрутиться через дефолтные значения. Но и они, кто бы мог подумать, не поддерживаются, приходится строить подпорки.

                          • +3
                            Вы, наверное, догадываетесь, что их там нет намеренно — на практике, по мнению авторов Go, удобство от наличия одноименных функций с разными сигнатурами параметров оказывается сбивающем с толку и запутывающим программистов. Этот вопрос есть в FAQ: golang.org/doc/faq#overloading
                            • +6
                              Я умею гуглить, спасибо.

                              Авторы могут считать как угодно. Я не собираюсь говорить им как они должны делать свой язык. просто меня раздражает отсутствие возможности сделать что-то в стиле
                              func f(n int := 0) {
                                  // pass
                              }
                              

                              вместо вот таких не сбивающих с толку программистов решений.

                              Особенно после распаковки аргументов в Python (*args, **kwargs), с которым Go часто сравнивают.
                              • –2
                                Вы совершаете ту же ошибку, что и автор статьи — вы боретесь с языком. Вместо того, чтобы понять, как с его помощью решать проблему, вы пытаетесь понять, как с его помощью сделать так, как я привык в других языках.
                                Не нужно делать из variadic parameters попытку симулировать argument overloading. Поймите, что решить задачу (реальную задачу, которую должна решать программа) можно сделать несколько иным способом, кроме как «найти любой ценой способ передавать дефолтные значения». И ценой вашего болезненного раздражительного «отвыкания» будет более ясный и читабельный для других код.
                            • +1
                              Optional arguments можно реализовать через структуру с инициализацией с именованными полями.
                            • +4
                              Пишу на питоне когда нет особых требований к скорости исполнения, или на D — когда они есть. Счастлив в обоих случаях. Попытка освоить Go окончилась неудачей по причине отсутствия удовольствния при написании кода.
                              • +4
                                Пишу на го пол года, до этого где то год назад всё в нем не нравилось (первый подход )), но появился проект в котором нужно было написать сложную бизнес логику, работающую по крайней мере не медленно, и всё это за 4 месяца. На java писать не хотел, на Си не умел, нужен был язык который изучишь быстро, в итоге выбор пал на го, и я не разочарован. Как оказалось на го писать легко и приятно, есть возможности профилирования памяти и процессора, быстрая компиляция, стандартная библиотека которая охватывает почти всё. Среду разработки использую LiteIDE, выглядит страшновато, зато работает быстро и всё что нужно есть. Писать тесты на нем легко и приятно. Ну и то что он активно развивается и имеет отзывчивое сообщество это также на мой взгляд огромный плюс. Пока я работал над проектом они выпустили новую версию GC которая уменьшила задержки до неприлично малых значений. Проект в итогде в продакшене, будем смотреть :)
                                • 0
                                  Я меня практический опыт работы с GO всего пару месяцев. Пока вообще далек от проблем в статье, и не факт, что когда-то они передо мной встанут. Сейчас пишу веб-приложение для одного сайта и в целом очень доволен.
                                  Отмечу плюсы:
                                  — язык очень простой
                                  — довольно строгие правила синтаксиса, я понимаю все чужие исходники и думаю другие легко будут понимать, что написал я
                                  — доступны исходники стандартных библиотек
                                  — компилируемость, отпадает потребность хранить исходники на сервере
                                  Из минусов:
                                  — не хватает оператора ( условие? выражение: выражение )
                                  — не такие большие сообщество и база знаний. Не всегда удается найти готовые решения или ответы.
                                • –40
                                  перевод статьи опытного разработчика о его опыте практического применения Go.

                                  Итак, прошел год с тех пор, как я начал использовать Go.


                                  Н-да… о-о-о-огромный опыт… — 1 год попробовал Go.

                                  Статья — бред!
                                  … обиженной девки, надувшей губки: «я такая красивая, а он меня не любит...»
                                  • +9
                                    А аргументы кроме ad hominem у вас есть?
                                    • –30
                                      аргументы в том, что 1 год — это не тот опыт чтобы рот раскрывать?
                                      • +20
                                        Во-первых, учитывая, что Go всего три года — это вполне ощутимый срок.
                                        Во-вторых, за год можно получить достаточное количество как положительных, так и отрицательных впечатлений о языке и инструментарии, которые и изложить в статье.

                                        Но это все не важно, потому что аргумент «один год — не тот опыт, чтобы» — это и есть аргумент ad hominem. В посте изложены вполне конкретные вещи; спорьте с ними, а не с личностью автора.
                                        • –4
                                          Go всего три года — это вполне ощутимый срок.

                                          не 3, а 6
                                          • +5
                                            Go 1 вышел в марте 2012. Но даже если шесть — это все равно не меняет остальной аргументации.
                                    • –32
                                      Вань! Ты посмотри какие клоуны — рот хоть завязочки пришей!


                                      Н-да… сильно я разрушил единомыслие и согласие в таком дружном семействе…

                                      Ты глянь, как по минусам тыцкают! ;-)

                                      • +4
                                        По вашему невозможно быть опытным разработчиком без опыта использования Go? И сколько лет должен проработать c Go человек, писавший скажем всю жизнь на Си, чтобы иметь право высказывать свое мнение?
                                        • –19
                                          По вашему невозможно быть опытным разработчиком без опыта использования Go?


                                          … в WEB-программировании? ;-)
                                          … или в этом… в DevOps-се? ;-) ;-)

                                          Обсуждать вкус устриц хотелось бы с теми, кто их пробовал.

                                          (с) М.Жванецкий
                                          • +3
                                            или в этом… в DevOps-се? ;-) ;-)
                                            Вот есть такие ребята. У них всё на Go написано, номады всякие с консулами. Логично, что люди, которые крутятся в этой кухне, пытаются пробовать Go, потому что авторы Go его для этого самого и позиционируют. Системный язык из Go не получился, остался пресловутый web и DevOps. Кто по вашему должен составлять мнение о Go в таком случае, бородатые системные программисты?
                                            • +3
                                              Сама фраза «системный язык» имеет различные смыслы. Вот в этом видео Александреску, Матсакиса, Страуструпа и Пайка спрашивают как раз один из вопросов про то, что вы считаете «системным языком».

                                              Поэтому, если уж дискутировать о позиционировании, давайте озвучим факт, что под этим термином разные люди понимают разные вещи. Кому-то кажется, что они должны писать собственные аллокаторы, а кому-то важно писать продуктивные программы для облаков.
                                              • 0
                                                Кстати в Go реально написать свой аллокатор, с помощью syscall.Mmap и unsafe.Pointer например.
                                                • –1
                                                  Под «системным языком» можно понимать что угодно, но есть чёткие определения, что такое «прикладное ПО» и «системное ПО». На Go пишут прикладное ПО.

                                                  Я к Go отношусь совершенно нейтрально, язык свою нишу нашёл, и его используют. Я просто не понимаю, что хотел сказать товарищ выше и что он понимает под вкусом устриц. Но ему, наверное, лучше знать с высоты его 40 лет опыта в программировании. :)
                                                  • –5
                                                    Под «системным языком» можно понимать что угодно, но есть чёткие определения, что такое «прикладное ПО» и «системное ПО».


                                                    Нука, нука… Определение — в студию.
                                                    Желательно со ссылкой на авторитетный источник.
                                                    • +1
                                                      Я понимаю, что за 40 лет можно всё забыть, в том числе всякие скучные определения, но как искать в гугле, я думаю, вы помните. Выжпрограммист.
                                                      • 0
                                                        Вы не правы. Вам выше привели ссылку на то, где авторы 4х системных языков объясняют, что определения размыты и подразумевают разные вещи.
                                                        Зачем писать «четкие определения», если они заведомо не четкие, и их нет, и даже ссылки на субъективные определения, справедливые для какой-то одной эпохи, вы не можете нагуглить?
                                                        • +1
                                                          Хорошо, если вам не нравится слово «чёткие», пусть они будут просто «определениями». Вы о чем спорите вообще, что хотите сказать? В любую, так называемую эпоху были программы, которые обеспечивали работу других программ.

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

                                                          (если что, минус не мой :)
                                                • 0
                                                  Я не защитник гоу, но все таки считаю что ваш аргумент про системный язык требует аргументации.
                                                  • 0
                                                    Я же написал, что «системный язык не получился». Эту мысль можно проследить из этого интервью: sourcegraph.com/blog/live/gophercon2015/123645585015
                                                    Q: You mentioned initially having the clear target of being a systems language was important. Is that still the target or has the target changed?

                                                    A: At this point, we really think of Go as a general purpose language. That’s also how people use it. It’s being used across the spectrum, and so that’s how we feel at this point.

                                                    Q: Most users of Go seem to be server-side. Do you think one way to make Go more mainstream is to attract more client-side developers.

                                                    A: The original design was not a standard general purpose language; it was a systems server-side programming language. There’s no ui package, for instance. Now that it’s general purpose, we would really like a ui package, but it’s a lot of work to come up with something that’s cross platform. We could use a lot of experts from the Go community here.
                                                    Создатели языка сами позиционируют его как язык общего назначения, на таких языках обычно не пытаются всерьёз писать драйверы устройств, ядра операционных систем или прошивки для микроконтроллеров, но для написания достаточно низкоуровневого server-side кода он вполне подходит.
                                              • +8
                                                Должен проработать, пока не полюбит Go, очевидно же.
                                                • +1
                                                  Видимо сей комментатор посчитал, что о языке можно писать лишь после его забвения. Через пять-десять лет мы получим первое поколение опытных АЛГОЛ-программистов и пойдут первые реально хорошие рецензии от опытных разработчиков. К 2030 ждем хороших рецензий на Паскаль, а Java столь молода, что на ней априори пишут лишь юниоры.
                                              • +2
                                                Я не считаю GoLang — инструментом для всего подряд, в нем есть полезные вещи как горутины и каналы, поэтому сетевые задачи на нем решать удобно, а в других задачах он уступает другим инструментам.
                                                • +2
                                                  Что такое «сетевые» задачи? Автор поста пишет, что невозможно изменить параметры создания сокета, не используя syscall — это вообще что хрень такая-то? Нафига тогда го, если есть С?
                                                  «Go нужен хорош для сетевого программирования» — мантра которую все повторяют, но видимо уже забыли, что это вообще значит.
                                                  • 0
                                                    Очевидно, имеется ввиду не столько «сетевое», сколько «многозадачное с долгими ожиданиями событий для продолжения задач», когда создавать по потоку на каждую задачу — дорого, а делать всё в один поток — медленно. Спасением тут является кооперативная многозадачность (горутины, гринлеты, волокна, легковесные потоки). Многие языки поддерживают её в той или иной мере: Go, NodeJS, Python, D, Rust, C# да в общем любой современный язык.
                                                    • 0
                                                      Очевидно, имеется ввиду не столько «сетевое», сколько «многозадачное с долгими ожиданиями событий для продолжения задач», когда создавать по потоку на каждую задачу — дорого, а делать всё в один поток — медленно.
                                                      Это само собой.

                                                      Многие языки поддерживают её в той или иной мере
                                                      Да, но не так хорошо: NodeJs, Python, D, Rust, C# — там либо async+await либо yield либо callback-hell. Хотя в Python есть gevent, но результат выходит гораздо медленнее чем на Go. Вот Erlang — конкурент, но он мне не очень нравится, может ещё какой-то язык подскажите? Вот Rust был бы не плох, но там нет микро-тредов либо с ними беда. Поэтому для меня решения на Go в качестве «сетевых тулзов» на первом месте, (для веба и тяжелых расчетов он уступает питону, с++ и другим).
                                                      • –1
                                                        Не вижу принципиальной разницы между await+async, go+chan и yield+run. Во всех упомянутых языках кооперативная многозадачность реализуются примерно одинаково.

                                                        Кто бы сомневался, что Python медленнее Go.

                                                        Подсказать могу — D на голову лучше Go. Когда наиграетесь в гопесочнице — добро пожаловать во взрослую джизнь :-)

                                                        Насчёт легковесных потоков в Rust не знаю — он такой же как Go в том смысле, что дизайн крутится вокруг одной единственной фичи, а остальные не реализуются с отпиской «это сложно в реализации поэтому не нужно» (я про исключения, не говоря уж про лисповые условия).
                                                        • 0
                                                          Не вижу принципиальной разницы между
                                                          Разница есть, в await и yield, ф-ии и библиотеки разделяются на 2 типа, при этом есть проблемы вызова одних типов из других. В go только один тип, поэтому такой проблемы нет и не нужно городить «синтаксический мусор».

                                                          Подсказать могу — D на голову лучше Go.
                                                          В нем тот же yield, а С/С++ он не заменит из-за скорости (а если скорость не нужна тогда можно заюзать хоть питон).

                                                          дизайн крутится вокруг одной единственной фичи, а остальные не реализуются с отпиской «это сложно в реализации поэтому не нужно»
                                                          Согласен, но это совсем другая история :).
                                                          • 0
                                                            1. Один тип легко преобразуется в другой.
                                                            2. Далеко не во всех языка есть эта разница.

                                                            1. Там те же волокна, что и в Go и нету костыльных «генераторов».
                                                            2. С чего бы ему быть медленней, если он такой же компилируемый, с опциональным сборщиком мусора и кастомизируемыми аллокаторами памяти?

                                                            • 0
                                                              1. Один тип легко преобразуется в другой.
                                                              Это не так, попробуйте преобразовать Django в async+await…
                                                              Какие-то небольшие библиотеки ещё можно преобразовать, но кто потом их будет поддерживать?, и опять же — раздвоение на 2 типа.

                                                              1. Там те же волокна
                                                              Вот это уже получше, попробовал — не плохо. Но раздвоение сохраняется, например vibe.d дублирует функционал стандартной библиотеки. Хотя для мелких проектов это не страшно. Надо будет проверить на сколько fiber быстрее/медленнее чем корутины от го.

                                                              2. С чего бы ему быть медленней,
                                                              Где то на dlang сайте вычитал — они рекомендуют использовать C если нужна бо'льшая скорость, хотя судя по мелким тестам пользователей он почти не отстает от c/c++.

                                                              Вообщем, язык интересный, только похоже комьюнити очень маленькое, проблема с докой и примерами, возможно попробую его на какой-нибудь мелкой задаче.
                                                              • +2
                                                                > Это не так, попробуйте преобразовать Django в async+await…

                                                                Беглое гугление: http://media.codysoyland.com/pdf/django-on-gevent.pdf

                                                                > Но раздвоение сохраняется, например vibe.d дублирует функционал стандартной библиотеки.

                                                                А он-то тут при чём?

                                                                > Где то на dlang сайте вычитал — они рекомендуют использовать C если нужна бо'льшая скорость

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

                                                                > Вообщем, язык интересный, только похоже комьюнити очень маленькое

                                                                Ну да, его не пиарят на каждом углу как сабж.
                                                                • 0
                                                                  Беглое гугление
                                                                  Это не то, не микро-треды, я специально написал «async+await», можете не гуглить, за это никто не возьмется.

                                                                  А он-то тут при чём?
                                                                  Я его попробовал в качестве асинхрононнго фреймворка работающего с сетью, дак вот он частично дублирует стандартную либу, про что я и говорил.
                                                                  Если не vibe.d то что использовать для асинхронной работы с сетью?
                                                                  • 0
                                                                    gevent — это те самые «микротреды», о которых шла речь в этой ветке http://www.gevent.org/
                                                                    Что именно вы вкладываете в async-await мне не ведомо.

                                                                    Там есть разные либы, но vibe.d наиболее богатая в этом плане. Это же хорошо, когда у вас есть выбор между несколькими реализациями одного функционала, конкуренция, все дела, разве нет? :-)
                                                                • 0
                                                                  Основная проблема с D, которая я вижу — отсутствие продвижения языка каким-нибудь монстром. Из этой проблемы вытекают более мелкие, но не критичные: слабый выбор IDE, органиченный выбор сторонних библиотек и фреймворков,. Однако качество языка и стандартных библиотек продаёт само себя, поэтому надеюсь что в ближайшее время ситуация исправится.
                                                                  • 0
                                                                    Сделал docker для D lang, кто хочет попробовать, запускать так:
                                                                    > docker run -it lega911/dlang
                                                                    # dmd --version
                                                                • 0
                                                                  > В go только один тип, поэтому такой проблемы нет и не нужно городить «синтаксический мусор».
                                                                  Судя по короткому экскурсу в std.concurrency D — тамошние файберы работают как горутины и Fiber.yield возвращает с любого уровня вложенности вызовов => синтаксический мусор не нужен.
                                                                  • 0
                                                                    Fiber.yield возвращает с любого уровня вложенности вызовов
                                                                    Кстати в этом есть плюс — мы контролируем когда нам переключится, значит для глобальных/общих объектов в пределах потока локи не нужны в отличие от Го.
                                                                    • 0
                                                                      И минус — вы должны четко понимать, кто за кем следует, дабы не допустить блокировки или лишнего ожидания корутин. По сути вы выполняете работу планировщика, только вручную. Более того, ваши коллеги должны быть крайне внимательны при работе с таким кодом — наличие незащищенного shared state не является потокобезопасным, но у вас возможна работа с ним из разных потоков управления, что вызывает вопросы. Лично я такое решение считаю не очень удачным, и крайне не устойчивым — есть большая вероятность отстрела ноги, а ловить такие баги потом крайне неприятно и долго.
                                                                      • –2
                                                                        И минус — вы должны четко понимать, кто за кем следует
                                                                        Да там полно минусов, поэтому горутины из Го — это значимая фича.
                                                                        • 0
                                                                          В D состояние по умолчанию не разделяется между потоками. Правда реализация передачи сообщений между ними использует блокировки. Не знаю, почему не реализовали неблокирующую очередь сообщений.
                                                                          • 0
                                                                            Так в Go тоже же самое, просто эти yield-ы спрятаны внутрь операторов работы с каналами и код работы с сетевым i/o. Я же говорю, файберы из D _по сути_ идентичны горутинам.

                                                                            Там могут быть различия в реализации, но суть та же.
                                                                    • +4
                                                                      > D на голову лучше Go
                                                                      Не, ну давайте все же будем честны — в плане concurrent рантайма и интеграции его с event loop D до Go еще расти и расти, а кто будет за это платить — неясно.
                                                                      • 0
                                                                        Ну я так понимаю Александреску лично возглавит. С шашкой и на белом коне.
                                                                        • +1
                                                                          Что же в Go такого удивительного в рантайме и интеграции? Я вижу лишь небольшую разницу в синтаксисе.
                                                                          • 0
                                                                            Ничего удивительного там нет, однако уже есть годный multicore планировщик с work stealing и уже написан неплохой враппер для асинхронного i/o на горутинах.

                                                                            Повторюсь, для Go оно уже есть, для D — непонятно когда будет и будет ли. Вся разница в этом.
                                                                            • 0
                                                                              Давно уже есть: https://gist.github.com/nin-jin/5f6969cb9063b1977769#file-coroutine-d — полный эквивалент горутин. Можно даже синтаксис сделать такой же приятный.
                                                                              В Go варианте вывод какой-то странный — по две итерации каждой горутиной. В D в один поток они просто чередуются (в примере — два).
                                                                              • 0
                                                                                Не буду спорить, с D я не могу так навскидку разобраться, как там рантайм устроен.
                                                                                • 0
                                                                                  Честно говоря — тяжело читать, у D нет своего онлайн компилятора?

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

                                                                                  Я мельком глянул vibe.core.stream — как я понял, там для неблокирующей операции нужно опросить ОС сколько уже готово, вручную.
                                                                                  • 0
                                                                                    Внезапно нашёл: http://dpaste.dzfl.pl/

                                                                                    Ну, запустите writeln в отдельном потоке.

                                                                                    Напишите один раз и вынесите в отдельную обобщённую функцию. А если ещё и опубликуете это модулем в репозитории, но получите плюс к карме. :-)
                                                                                  • 0
                                                                                    В Go варианте вывод какой-то странный — по две итерации каждой горутиной.
                                                                                    Возможно они в разных потоках, при этом в одной горутине принт срабатывает чуть позже, а после sleep чуть раньше, и выглядит как будь-то они «слипаются».

                                                                                    Разница такая — если одна горутина заблокируется (бесконечный цикл или блокирующее io), то D приложение встанет колом, когда в Го приложение будет работать, Mikanor про это отписался.
                                                                                    • 0
                                                                                      Горутины выполняются параллельно, когда это возможно по мнению планировщика. Отсюда некая недетерминированность I/O. В примере на D sleep выполняются асинхронно, но друг за другом, в том время как в го асинхронно, но параллельно.
                                                                                      • 0
                                                                                        В примере на D даже глобальные состояния разные. О чём вы?
                                                                                      • 0
                                                                                        Судя по цифрам — они либо в одном потоке, которого вполне хватает для таких задач, либо в разных, но разделяют одно состояние, что ещё хуже.

                                                                                        Что ж вы придираетесь-то к простому примеру? Если вы заблокируете основной поток, то у вас на любом языке приложение встанет колом. Поэтому реальные задачи запускаются только в воркерах.

                                                                                        • 0
                                                                                          Для интереса сделал набросок балансировщика на dlang + vibe.d, тут не весь функционал и он уже отстает от версии на го на ~15-20% (запускал их в одном потоке + 10 клиентов и 10 ворекров). Может там нужно что-то «подтюнить»?
                                                                                          • 0
                                                                                            Не очень понял что там происходит. Может целиком бенчмарк выложите, чтобы я его мог у себя погонять?
                                                                                            • 0
                                                                                              Ох, как руки дойдут, но обещать не буду. Надо будет упростить скрипты, просто сделать проксирование.
                                                                                              • 0
                                                                                                Начал делать скрипт и с dlang беда какая-то — не возможно получить точное время, нашел рецепт, но он дает расхождения в 10 сек и более. Куда копать?
                                                                                                • 0
                                                                                                  Подозреваю дело в том, что там считается ещё и время вывода в консоль, лови пул-реквест.
                                                                                                  • 0
                                                                                                    С текущей версий тестов получились такие результаты:
                                                                                                    Dlang
                                                                                                    
                                                                                                    26572
                                                                                                    26607
                                                                                                    26678
                                                                                                    26678
                                                                                                    ...
                                                                                                    
                                                                                                    Go
                                                                                                    
                                                                                                    33764
                                                                                                    33292
                                                                                                    33787
                                                                                                    33403
                                                                                                    ...
                                                                                                    

                                                                                                    Го быстрее на 26%.
                                                                                                    • 0
                                                                                                      Какой компилятор для D использовался?
                                                                                                      • 0

                                                                                                        dmd, очевидно.

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

                                                                                                          lega, повторите тест используя GDC или LDC?
                                                                        • 0
                                                                          А со скоростью как в этих сетевых задачах?
                                                                          • 0
                                                                            У меня есть балансировщик для rpc на python + zeromq и аналогичный на golang, дак вот версия на golang в 3-4 раза производительней (что не удивительно). Кроме этого, не прямые конкурентные решения на C/C++ и Erlang работают медленнее (в разы), хотя в первую очередь это связано с набором фич, и производительность языков тут не сравнить.

                                                                            Вполне возможно на С++ написать ещё более быструю версию, но возится с асинхронностью и процессами, что берет на себя GoLang из коробки, для меня не оправдано.
                                                                            • 0
                                                                              golang версия тоже через zeromq работает?
                                                                              • 0
                                                                                Нет, но основная логика приложения та же, (не думаю что ручная работа с сокетами и селектами в питоне даст больший профит чем через zmq).
                                                                              • 0
                                                                                , дак вот версия на golang в 3-4 раза производительней (что не удивительно)

                                                                                Это очень удивительно, ищите ошибки в архитектуре rpc на python + zeromq, такого не может быть.
                                                                                • +2
                                                                                  такого не может быть.
                                                                                  Не может быть что питон медленнее чем golang? Я думаю это очевидно что питон медленнее. Вот код.
                                                                                  • 0
                                                                                    Питон медленнее Го, но не в три-четыре раз, плюс речь идет о сетевом приложении, где основные тормоза это ожидание готовности ввода/вывода. И если у вас похожая архитектура, во всяком случае и там, и там асинхронная обработка сетевых подключение, то 3-4 раза очень и очень сомнительно.

                                                                                    Готов забрать свои слова назад, если представите адекватные тесты.
                                                                                    • 0
                                                                                      Питон медленнее Го, но не в три-четыре раз
                                                                                      Да, не в три-четыре, а больше, если сравнивать скорость исполнения питон-байткода.
                                                                                      Например можете запустить у себя эти 2 цикла, у меня го выполняет в 100 раз быстрее. А в одном реальном проекте был расчет математики и я получил ускорение в 17 раз (и ещё больше при C++).
                                                                                      А вот исходники тех самых балансировщиков, py и го.

                                                                                      У Python'а много других достоинств, и Го там рядом не стоит. (Поэтому я на сервер-сайде использую Python, GoLang, C++ совместно для разных задач).
                                                                                      • 0
                                                                                        Пустые циклы очень хорошо оптимизируются компиляторами, удивляюсь что только в 100 раз :)
                                                                                        Математика да, операции с плавающими числами в питоне медленные. Математику в питоне или не считают или считают с использованием специализированных пакетов типа numpy, насколько я знаю.

                                                                                        Скажите сколько ядер на машине, где вы сравнивали Go и Python код вышеприведенный?
                                                                                        • 0
                                                                                          Пустые циклы очень хорошо оптимизируются компиляторами
                                                                                          Такие циклы обрезаются умными компиляторами, но это не тот случай.

                                                                                          Математику в питоне или не считают или считают с использованием специализированных пакетов типа numpy, насколько я знаю.
                                                                                          Да, питон достаточно быстрый для своих задач за счет того что многие модули написаны на C/C++.

                                                                                          Скажите сколько ядер на машине
                                                                                          2, но это не имеет значения для данного теста (Во всех тестах я делал с ограничением в одно ядро и без).
                                                                                          • –2
                                                                                            но это не тот случай

                                                                                            Почему, очень похоже именно на этот случай.

                                                                                            Во всех тестах я делал с ограничением в одно ядро и без

                                                                                            А как вы добились того, что бы Go не форкался автоматом по числу ядер?
                                                                                            • 0
                                                                                              очень похоже именно на этот случай.
                                                                                              Если бы цикл вырезался, то приложение не задерживалось бы на 0.4 сек (на 4 сек при увеличении цикла в х10 раз). Для уверенности можете какую-нибудь сложную математику протестировать.

                                                                                              что бы Go не форкался автоматом по числу ядер?
                                                                                              Это управляется с помощью GOMAXPROCS
                                                                                              • 0
                                                                                                Для уверенности можете какую-нибудь сложную математику протестировать.
                                                                                                Математику не стоит, она очень плоха в питоне из коробки, просто делайте что-то в цикле, хотя бы просто инкременируйте переменную.

                                                                                                Как тестите эти два приложения? Есть такая штука github.com/joshmarshall/tornadorpc
                                                                                                было бы интересно сделать аналог на нем и посмотреть.
                                                                                      • 0
                                                                                        Погонял у себя примитивный тест lega (но с py версией с «while i < 1000000000»), Python вообще в 184 раза медленнее Go получился…
                                                                                        • 0
                                                                                          А вот это даже как-то странно.
                                                                                          • 0
                                                                                            Я как раз с while и гонял, написал же.
                                                                                            • 0
                                                                                              Сори, не внимательно прочитал сперва :-)
                                                                                              • 0
                                                                                                Причем, 184 раза это python2.7. На python3.4 разница вобще в 275 раз.
                                                                                                • 0
                                                                                                  Можете, ради интереса, попробовать запустить на pypy, — не будет отставать* от golang, если не обгонит.
                                                                                                  • 0
                                                                                                    pypy медленнее Go в 14 раз…
                                                                                                    • 0
                                                                                                      Я чуть поправил py код:
                                                                                                      import time
                                                                                                      
                                                                                                      def main():
                                                                                                          i = 0
                                                                                                          while i < 1000000000:
                                                                                                              i += 1
                                                                                                      
                                                                                                      start = time.time()
                                                                                                      main()
                                                                                                      finish = time.time()
                                                                                                      print(finish-start)
                                                                                                      


                                                                                                      pypy 2.2: 650ms
                                                                                                      golang: 405ms

                                                                                                      т.е. pypy получился медленнее на ~40%
                                                                                                      • 0
                                                                                                        Да, так уже лучше: у меня разница всего в два раза примерно (6.0 против 3.5).
                                                                                                        • 0
                                                                                                          Добавил в циклы суммирование всех значений i:
                                                                                                          go — 6сек
                                                                                                          pypy — 165сек

                                                                                                          Разница 27 раз. Ну я так не играю)
                                                                                                          • 0
                                                                                                            Возможно из за того, что в этом случае в Го используется long*, когда pypy думает что результат может выйти за 8 байт и переключается на «bigint», а он гораздо медленнее.
                                                                                                            • 0
                                                                                                              Скорее всего. Если не допустить выхода за пределы разница всего в полтора раза.
                                                                                                            • 0
                                                                                                              А я добавил D — он в 2 раза быстрее чем Go отработал.

                                                                                                              https://gist.github.com/lega911/c4b627c3f17625f05d44#gistcomment-1595006
                                                                                                              • 0
                                                                                                                dub это уже скомпиленное? Может тогда и Go запускать уже скомпиленное?