Go (язык программирования) - Go (programming language)

Идти
Go Logo Blue.svg
Парадигма Мультипарадигма : параллельная , функциональная , императивная , объектно-ориентированная
Разработано Роберт Гриземер
Роб Пайк
Кен Томпсон
Разработчик Авторы Go
Впервые появился 10 ноября 2009 г . ; 11 лет назад ( 2009-11-10 )
Стабильный выпуск
1.17.1  Отредактируйте это в Викиданных / 9 сентября 2021 г . ; 40 дней назад ( 9 сентября 2021 г. )
Печатная дисциплина Предполагаемый , статический , прочный , конструктивный , номинальный
Язык реализации Go, язык ассемблера (gc); C ++ (gofrontend)
Операционные системы DragonFly BSD , FreeBSD , Linux , macOS , NetBSD , OpenBSD , Plan 9 , Solaris , Windows
Лицензия 3-положение BSD + патент грант
Расширения имени файла .идти
Веб-сайт golang .org
Основные реализации
gc, gofrontend
Под влиянием
C , Оберон-2 , Лимбо , Активный Оберон , взаимодействие последовательных процессов , Паскаль , Оберон , Smalltalk , Newsqueak , Модула-2 , Алеф , APL , BCPL , Модула , Оккам ,Эрланг,
Под влиянием
Один, Кристалл , Зиг

Go представляет собой статически типизированных , составленный язык программирования разработан в Google с помощью Роберт Грисемер , Роб Пайк и Кен Томпсон . Go синтаксически похож на C , но с безопасностью памяти , сборкой мусора , структурной типизацией и параллелизмом в стиле CSP . Этот язык часто называют Golang из-за его доменного имени , но собственное имя - Go. golang.org

Есть две основные реализации:

Сторонний компилятор преобразования исходного кода в исходный код , GopherJS, компилирует Go to JavaScript для интерфейсной веб-разработки .

История

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

Дизайнеры в первую очередь руководствовались общей неприязнью к C ++ .

Go был публично анонсирован в ноябре 2009 года, а версия 1.0 была выпущена в марте 2012 года. Go широко используется в производственной среде в Google и во многих других организациях и проектах с открытым исходным кодом.

Талисман языка программирования Go - изображенный выше Gopher .

В ноябре 2016 года шрифты Go и Go Mono были выпущены шрифтовыми дизайнерами Чарльзом Бигелоу и Крисом Холмсом специально для использования в проекте Go. Go - это гуманистический шрифт без засечек, напоминающий Lucida Grande, а Go Mono - моноширинный . Каждый из шрифтов соответствует набору символов WGL4 и был разработан так, чтобы быть разборчивым, с большой высотой по оси x и отличными формами букв. И Go, и Go Mono соответствуют стандарту DIN 1450, поскольку в них есть ноль с косой чертой, нижний регистр lс хвостиком и верхний регистр Iс засечками.

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

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

История версий

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

Каждый основной выпуск Go поддерживается до двух новых основных выпусков.

История версий Go
Основная версия Дата первого выпуска Изменения языка Прочие изменения
1–1.0.3 2012-03-28 Первый выпуск
1.1–1.1.2 2013-05-13
  • В Go 1.1 целочисленное деление на константу ноль недопустимо, поэтому это ошибка времени компиляции.
  • Определение строковых и рунных литералов было уточнено, чтобы исключить суррогатные половинки из набора допустимых кодовых точек Unicode.
  • Ослабленные правила требований к возврату. Если компилятор может доказать, что функция всегда возвращается до достижения конца функции, последний оператор завершения может быть опущен.
  • Язык позволяет реализации выбирать, являются ли intтип и uintтипы 32-битными или 64-битными.
  • На 64-битных архитектурах максимальный размер кучи был существенно увеличен с нескольких гигабайт до нескольких десятков гигабайт.
  • Добавление детектора гонок в стандартный набор инструментов.
1.2–1.2.2 2013-12-01
  • Теперь в языке указано, что из соображений безопасности определенное использование нулевых указателей гарантированно вызовет панику во время выполнения.
  • Go 1.2 добавляет возможность указывать емкость, а также длину при использовании операции нарезки для существующего массива или фрагмента. Операция нарезки создает новый фрагмент, описывая непрерывный раздел уже созданного массива или фрагмента.
  • Планировщик времени выполнения теперь можно вызывать при (не встроенных) вызовах функций.
  • Go 1.2 вводит настраиваемое ограничение (по умолчанию 10 000) на общее количество потоков, которые может иметь одна программа.
  • В Go 1.2 минимальный размер стека при создании горутины увеличен с 4 КБ до 8 КБ.
1.3–1.3.3 2014-06-18 В этом выпуске нет языковых изменений.
  • Модель памяти Go 1.3 добавляет новое правило, касающееся отправки и получения по буферизованным каналам, чтобы явно указать, что буферизованный канал может использоваться как простой семафор, используя отправку в канал для получения и получение из канала для освобождения.
  • Go 1.3 изменил реализацию стеков горутин от старой, «сегментированной» модели к непрерывной модели.
  • Некоторое время сборщик мусора был точен при проверке значений в куче; выпуск Go 1.3 добавляет эквивалентную точность к значениям в стеке.
  • Итерации по маленьким картам больше не происходят в последовательном порядке. Это связано с тем, что разработчики злоупотребляют поведением реализации.
1.4–1.4.3 2014-12-10
  • Выражение-диапазон без присваивания
  • Автоматическое двойное разыменование вызовов методов теперь запрещено в gc и gccgo. Это обратно несовместимое изменение, но оно соответствует спецификации языка.
  • В версии 1.4 большая часть кода среды выполнения была переведена на Go, чтобы сборщик мусора мог сканировать стеки программ во время выполнения и получать точную информацию о том, какие переменные активны.
  • Язык , принятые монтажниками cmd/5a, cmd/6aи cmd/8aбыл несколько изменений, главным образом , чтобы сделать его проще для доставки информации о типе для выполнения.
  • Добавление внутренних пакетов.
  • Новая подкоманда go generate.
1,5–1,5,4 2015-08-19

По недосмотру правило, позволяющее исключить тип элемента из литералов среза, не применялось к ключам карты. Это было исправлено в Go 1.5.

  • Компилятор и среда выполнения теперь реализованы на Go и ассемблере без C. Теперь, когда компилятор Go и среда выполнения реализованы в Go, компилятор Go должен быть доступен для компиляции дистрибутива из исходного кода. Компилятор теперь размещен на собственном сервере.
  • Сборщик мусора был переработан для версии 1.5. Фаза «остановки мира» коллектора почти всегда будет меньше 10 миллисекунд, а обычно намного меньше.
  • В Go 1.5 порядок, в котором планируются горутины, был изменен.
1.6–1.6.4 2016-02-17 В этом выпуске нет языковых изменений.
  • Существенное изменение было внесено в cgo, определяющее правила совместного использования указателей Go с кодом C, чтобы гарантировать, что такой код C может сосуществовать со сборщиком мусора Go.
  • Парсер Go теперь написан вручную, а не сгенерирован.
  • Теперь go vetкоманда диагностирует передачу значений функции или метода в качестве аргументов Printf, например, при передаче, fгде f()было предназначено.
1,7–1,7,6 2016-08-15

Разъяснение по поводу завершающих операторов в спецификации языка. Это не меняет существующего поведения.

  • Для 64-битных систем x86, следующие инструкции , которые были добавлены (см SSE ): PCMPESTRI, RORXL, RORXQ, VINSERTI128, VPADDD, VPADDQ, VPALIGNR, VPBLENDD, VPERM2F128, VPERM2I128, VPOR, VPSHUFB, VPSHUFD, VPSLLD, VPSLLDQ, VPSLLQ, VPSRLD, VPSRLDQ, и VPSRLQ.
  • Этот выпуск включает в себя новую серверную часть генерации кода для 64-разрядных систем x86 на основе SSA .
  • Пакеты, использующие cgo, теперь могут включать исходные файлы Fortran (в дополнение к C, C ++, Objective C и SWIG), хотя привязки Go по-прежнему должны использовать API-интерфейсы языка C.
  • Новая подкоманда « go tool dist list» выводит все поддерживаемые пары операционная система / архитектура.
1,8–1,8,7 2017-02-16

При явном преобразовании значения из одного типа структуры в другой, начиная с Go 1.8, теги игнорируются. Таким образом, две структуры, которые отличаются только своими тегами, могут быть преобразованы из одной в другую.

  • Для 64-битных систем x86, следующие инструкции , которые были добавлены: VBROADCASTSD, BROADCASTSS, MOVDDUP, MOVSHDUP, MOVSLDUP, VMOVDDUP, VMOVSHDUP, и VMOVSLDUP.
  • Паузы при сборке мусора должны быть значительно короче, чем в Go 1.7, обычно менее 100 микросекунд и часто всего 10 микросекунд. Подробные сведения см. В документе об исключении необходимости повторного сканирования стопки при остановке.
  • Накладные расходы на отложенные вызовы функций сократились примерно вдвое.
  • Накладные расходы на вызовы из Go в C сократились примерно вдвое.
1.9–1.9.7 2017-08-24
  • Go теперь поддерживает псевдонимы типов.
  • Принудительное промежуточное округление в арифметике с плавающей запятой.

Компилятор Go теперь поддерживает параллельную компиляцию функций пакета, используя преимущества нескольких ядер.

1.10–1.10.7 2018-02-16
  • Был прояснен угловой случай, связанный со сдвигами нетипизированных констант.
  • Грамматика для выражений методов была обновлена, чтобы ослабить синтаксис и разрешить любое выражение типа в качестве получателя.

Для 64-разрядного порта x86 ассемблер теперь поддерживает 359 новых инструкций, включая полные наборы расширений AVX, AVX2, BMI, BMI2, F16C, FMA3, SSE2, SSE3, SSSE3, SSE4.1 и SSE4.2. Ассемблер также больше не реализует MOVL $0, AXкак XORLинструкцию, чтобы избежать неожиданной очистки флагов условий.

1.11–1.11.6 2018-08-24 В этом выпуске нет языковых изменений.
  • Go 1.11 добавляет экспериментальный порт в WebAssembly .
  • В Go 1.11 добавлена ​​предварительная поддержка новой концепции, называемой «модули», альтернативы GOPATH с интегрированной поддержкой управления версиями и распространения пакетов.
  • Ассемблер amd64пока принимает инструкции AVX512.
  • Go 1.11 отказывается от поддержки Windows XP и Windows Vista.
  • Go 1.11.3 и более поздние версии исправляют уязвимость аутентификации TLS в пакете crypto / x509.
1.12.1 2019-02-25 В этом выпуске нет языковых изменений.
  • Подписка на поддержку TLS 1.3
  • Улучшенная поддержка модулей (готовится к использованию по умолчанию в Go 1.13)
  • Поддержка для windows/arm
  • Улучшенная совместимость с macOS и iOS.
1.13.1 2019-09-03

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

  • поддержка TLS 1.3 в пакете crypto / tls по умолчанию (отказ будет удален в Go 1.14)
  • Поддержка упаковки ошибок
1.14 2020-02-25

Позволяет встраивать интерфейсы с перекрывающимися наборами методов

Поддержка модуля в goкоманде теперь готова к производственному использованию

1,15 2020-08-11 В этом выпуске нет языковых изменений.
  • Новый встроенный пакет time / tzdata
  • Глаголы печати %#gи %#Gтеперь сохраняют конечные нули для значений с плавающей запятой
  • Пакет reflectтеперь запрещает доступ к методам всех неэкспортируемых полей, тогда как ранее он разрешал доступ к методам неэкспортированных встроенных полей.
1,16 2021-02-16 В этом выпуске нет языковых изменений.
  • Новая поддержка встраивания файлов в программу Go
  • Поддержка macos / arm
  • Режим с поддержкой модулей включен по умолчанию
1.17 2021-08-16 В этом выпуске нет языковых изменений.
  • Это обновление в первую очередь изменяет внутреннее устройство Go.

Дизайн

Go находится под влиянием C (особенно диалекта Plan 9), но с упором на большую простоту и безопасность. Язык состоит из:

Синтаксис

Синтаксис Go включает изменения по сравнению с C, направленные на то, чтобы код оставался лаконичным и читаемым. Комбинированный оператор декларации / инициализация был введен , что позволяет программисту писать i := 3или s := "Hello, world!", без указания типов переменных , используемых. Это контрастирует с C int i = 3;и const char *s = "Hello, world!";. Точки с запятой по-прежнему завершают операторы, но неявно используются в конце строки. Методы могут возвращать несколько значений, и возврат result, errпары - это обычный способ, которым метод сообщает об ошибке вызывающему объекту в Go. Go добавляет буквальные синтаксисы для инициализации параметров структуры по имени и для инициализации карт и срезов . В качестве альтернативы forциклу из трех операторов C rangeвыражения Go позволяют выполнять краткую итерацию по массивам, срезам, строкам, картам и каналам.

Типы

Go имеет ряд встроенных типов, включая числовые ( byte , int64 , float32 и т. Д.), Логические и символьные строки ( string ). Строки неизменны; встроенные операторы и ключевые слова (а не функции) обеспечивают объединение, сравнение и кодирование / декодирование UTF-8 . Типы записей можно определить с помощью ключевого слова struct .

Для каждого типа T и каждой неотрицательной целочисленной константы n существует тип массива, обозначенный [ n ] T ; Таким образом, массивы разной длины относятся к разным типам. Динамические массивы доступны в виде «срезов», обозначаемый [] T для некоторого типа T . Они имеют длину и емкость, определяющие, когда необходимо выделить новую память для расширения массива. Несколько фрагментов могут совместно использовать свою базовую память.

Указатели доступны для всех типов, а также указатель-to - T типа обозначаются * T . При приеме адреса и косвенном обращении используются операторы & и * , как в C, или неявно через вызов метода или синтаксис доступа к атрибуту. Нет арифметики с указателями, за исключением использования специального типа unsafe.Pointer в стандартной библиотеке.

Для пары типов K , V карта типов [ K ] V является типом хэш-таблиц, отображающих ключи типа K в значения типа V. Хеш-таблицы встроены в язык со специальным синтаксисом и встроенными функциями. chan T - это канал, который позволяет отправлять значения типа T между параллельными процессами Go .

Помимо поддержки интерфейсов , система типов Go является номинальной : ключевое слово type может использоваться для определения нового именованного типа , который отличается от других именованных типов, имеющих такой же макет (в случае структуры те же члены в в том же порядке). Некоторые преобразования между типами (например, между различными целочисленными типами) предопределены, и добавление нового типа может определять дополнительные преобразования, но преобразования между именованными типами всегда должны вызываться явно. Например, ключевое слово type можно использовать для определения типа адресов IPv4 на основе 32-битных целых чисел без знака:

type ipv4addr uint32

С этим определением типа ipv4addr (x) интерпретирует значение x uint32 как IP-адрес. Простое присвоение x переменной типа ipv4addr является ошибкой типа.

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

Типы функций обозначаются ключевым словом func ; они принимают ноль или более параметров и возвращают ноль или более значений, все из которых являются типизированными. Параметр и возвращаемые значения определяют тип функции; таким образом, func (string, int32) (int, error) - это тип функций, которые принимают строку и 32-разрядное целое число со знаком и возвращают целое число со знаком (ширины по умолчанию) и значение встроенного типа интерфейса. ошибка .

С любым именованным типом связан набор методов . Приведенный выше пример IP-адреса можно расширить с помощью метода проверки, является ли его значение известным стандартом:

// ZeroBroadcast reports whether addr is 255.255.255.255.
func (addr ipv4addr) ZeroBroadcast() bool {
    return addr == 0xFFFFFFFF
}

Из-за номинальной типизации это определение метода добавляет метод к ipv4addr , но не к uint32 . Хотя методы имеют особое определение и синтаксис вызова, отдельного типа метода не существует.

Система интерфейса

Go предоставляет две функции, которые заменяют наследование классов .

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

Во-вторых, это интерфейсы , обеспечивающие полиморфизм времени выполнения . Интерфейсы - это класс типов, которые обеспечивают ограниченную форму структурной типизации в системе Go с номинальными типами. Объект, который относится к типу интерфейса, также относится к другому типу, подобно объектам C ++, которые одновременно являются базовым и производным классами. Интерфейсы Go были разработаны на основе протоколов языка программирования Smalltalk. Во многих источниках при описании интерфейсов Go используется термин « утиная печать» . Хотя термин «утиная типизация» не определен точно и, следовательно, не является неправильным, он обычно подразумевает, что соответствие типа не проверяется статически. Поскольку соответствие интерфейсу Go проверяется компилятором Go статически (кроме случаев, когда выполняется утверждение типа), авторы Go предпочитают термин структурная типизация .

В определении типа интерфейса перечислены необходимые методы по имени и типу. Любой объект типа T, для которого существуют функции, соответствующие всем требуемым методам интерфейса типа I, также является объектом типа I. Определение типа T не обязательно (и не может) идентифицировать тип I. Например, если форма , квадрат и круг определены как

import "math"

type Shape interface {
    Area() float64
}

type Square struct { // Note: no "implements" declaration
    side float64
}

func (sq Square) Area() float64 { return sq.side * sq.side }

type Circle struct { // No "implements" declaration here either
    radius float64
}

func (c Circle) Area() float64 { return math.Pi * math.Pow(c.radius, 2) }

тогда как Square, так и Circle неявно являются Shape и могут быть присвоены переменной типа Shape . На формальном языке интерфейсная система Go обеспечивает структурную, а не номинальную типизацию. Интерфейсы могут встраивать другие интерфейсы с эффектом создания комбинированного интерфейса, которому удовлетворяют именно те типы, которые реализуют встроенный интерфейс, и любые методы, которые добавляет новый определенный интерфейс.

Стандартная библиотека Go использует интерфейсы для обеспечения универсальности в нескольких местах, включая систему ввода / вывода, основанную на концепциях Reader и Writer .

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

Пустой интерфейс interface{} является важной базой случая , потому что он может обратиться к пункту любого типа бетона. Он похож на класс Object в Java или C # и подходит для любого типа, включая встроенные типы, такие как int . Код, использующий пустой интерфейс, не может просто вызывать методы (или встроенные операторы) для указанного объекта, но он может сохранить interface{}значение, попытаться преобразовать его в более полезный тип с помощью утверждения типа или переключателя типа или проверить его. с reflectпакетом Go . Поскольку interface{}может ссылаться на любое значение, это ограниченный способ избежать ограничений статической типизации, как void*в C, но с дополнительными проверками типа во время выполнения.

interface{}Тип может быть использован для моделирования структурированных данных любой произвольной схемы в Go, такие как JSON или YAML данных, представляя его как map[string]interface{}(карта строки в пустой интерфейс). Это рекурсивно описывает данные в виде словаря со строковыми ключами и значениями любого типа.

Значения интерфейса реализуются с использованием указателя на данные и второго указателя на информацию о типе времени выполнения. Как и некоторые другие типы, реализованные с использованием указателей в Go, значения интерфейса не nilинициализированы.

Система пакетов

В системе пакетов Go каждый пакет имеет путь (например, "compress/bzip2"или "golang.org/x/net/html") и имя (например, bzip2или html). Ссылки на определения других пакетов всегда должны начинаться с префикса имени другого пакета, и доступны только имена с заглавной буквы из других пакетов: io.Readerявляется общедоступным, но bzip2.readerне является. Команда go getможет извлекать пакеты, хранящиеся в удаленном репозитории, и разработчикам рекомендуется разрабатывать пакеты внутри базового пути, соответствующего исходному репозиторию (например, example.com/user_name/package_name), чтобы уменьшить вероятность конфликта имен с будущими дополнениями к стандарту. библиотека или другие внешние библиотеки.

Существуют предложения по внедрению надлежащего решения для управления пакетами для Go, аналогичного CPAN для Perl или системы Cargo Rust или системы npm в Node .

Параллелизм: горутины и каналы

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

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

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

Каналы набирается, так что канал типа чан T может быть использован только для передачи сообщений типа T . Для работы с ними используется специальный синтаксис; <-ch - это выражение, которое заставляет выполняющуюся горутину блокироваться до тех пор, пока значение не поступит по каналу ch , в то время как ch <- x отправляет значение x (возможно, блокировка до тех пор, пока значение не будет получено другой горутиной). Встроенный переключатель -like выберите заявление может быть использована для реализации неблокируемой связи по нескольким каналам; см. ниже пример. В Go есть модель памяти, описывающая, как горутины должны использовать каналы или другие операции для безопасного обмена данными.

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

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

Связанные с параллелизмом структурные соглашения Go ( каналы и альтернативные входы каналов) получены из модели последовательных процессов взаимодействия Тони Хоара . В отличие от предыдущих языков параллельного программирования, таких как Occam или Limbo (язык, на котором работал соавтор Go Роб Пайк), Go не предоставляет никаких встроенных понятий безопасного или проверяемого параллелизма. Хотя в Go отдается предпочтение модели взаимодействующих процессов, она не единственная: все горутины в программе используют единое адресное пространство. Это означает, что изменяемые объекты и указатели могут совместно использоваться горутинами; см. § § Отсутствие безопасности в условиях гонки ниже.

Пригодность для параллельного программирования

Хотя функции параллелизма Go не нацелены в первую очередь на параллельную обработку , их можно использовать для программирования многопроцессорных машин с общей памятью . Были проведены различные исследования эффективности этого подхода. В одном из этих исследований сравнивали размер (в строках кода ) и скорость программ, написанных опытным программистом, не знакомым с языком, и исправления этих программ, сделанные экспертом по Go (из группы разработчиков Google), делая то же самое для Chapel , Cilk. и Intel TBB . Исследование показало, что неспециалисты, как правило, пишут алгоритмы « разделяй и властвуй» с одним оператором « go» на рекурсию, в то время как эксперт писал программы «распределение-работа-синхронизация» с использованием одной горутины на процессор. Программы эксперта были обычно быстрее, но и длиннее.

Отсутствие безопасности условий гонки

Нет никаких ограничений на то, как горутины получают доступ к общим данным, что делает возможными условия гонки . В частности, если программа явно не синхронизируется через каналы или другие средства, записи из одной горутины могут быть частично, полностью или вообще не видны для другой, часто без каких-либо гарантий порядка записи. Кроме того, внутренние структуры данных Go, такие как значения интерфейса, заголовки фрагментов, хэш-таблицы и заголовки строк, не защищены от условий гонки, поэтому безопасность типов и памяти может быть нарушена в многопоточных программах, которые изменяют общие экземпляры этих типов без синхронизации. Таким образом, вместо языковой поддержки безопасное параллельное программирование опирается на соглашения; например, Chisnall рекомендует идиому под названием «aliases xor mutable», означающую, что передача изменяемого значения (или указателя) по каналу сигнализирует о передаче права собственности на значение его получателю.

Двоичные файлы

Компоновщик в инструментальной цепочке gc по умолчанию создает статически связанные двоичные файлы; поэтому все двоичные файлы Go включают среду выполнения Go.

Упущения

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

Из пропущенных языковых функций разработчики явно возражают против утверждений и арифметики указателей, защищая при этом выбор об исключении наследования типов как предоставление более полезного языка, поощряя вместо этого использование интерфейсов для достижения динамической диспетчеризации и композиции для повторного использования кода. На самом деле композиция и делегирование в значительной степени автоматизированы за счет встраивания структур ; по мнению исследователей Schmager et al. , эта функция "имеет много недостатков наследования: она влияет на общедоступный интерфейс объектов, она не является детализированной (т.е. отсутствует контроль над внедрением на уровне метода), методы встроенных объектов не могут быть скрыты, и она статична. ", что делает" не очевидным ", будут ли программисты злоупотреблять им до такой степени, что программисты на других языках, как считается, злоупотребляют наследованием.

Разработчики выражают открытость к общему программированию и отмечают, что встроенные функции на самом деле являются общими типами, но они рассматриваются как особые случаи; Пайк называет это слабостью, которую в какой-то момент можно изменить. Команда Google создала по крайней мере один компилятор для экспериментального диалекта Go с дженериками, но не выпустила его. Они также открыты для стандартизации способов применения генерации кода. В июне 2020 года был опубликован новый черновой проект документа, который добавит в Go необходимый синтаксис для объявления общих функций и типов. Был предоставлен инструмент для перевода кода go2go, позволяющий пользователям опробовать новый синтаксис вместе с версией онлайн-игры Go Playground с универсальными шаблонами .

Первоначально опущенный, в конечном итоге был добавлен механизм паники / восстановления, подобный исключениям , который авторы Go советуют использовать для неисправимых ошибок, таких как те, которые должны остановить всю программу или запрос сервера, или в качестве ярлыка для распространения ошибок вверх по стеку внутри пакета. (но не за пределами пакета; там возврат ошибок - это стандартный API).

Стиль

Авторы Go приложили значительные усилия, чтобы повлиять на стиль программ Go:

  • Отступы, интервалы и другие поверхностные детали кода автоматически стандартизируются gofmtинструментом. golintавтоматически выполняет дополнительные проверки стиля.
  • Инструменты и библиотеки, распространяемые с Go, предлагают стандартные подходы к таким вещам, как документация по API ( godoc), тестирование ( go test), сборка ( go build), управление пакетами ( go get) и т. Д.
  • Go применяет правила, которые являются рекомендациями для других языков, например, запрещает циклические зависимости, неиспользуемые переменные или импорт, а также неявные преобразования типов.
  • Упущение некоторых функций (например, ярлыки функционально-программирование , как mapи Java-стиль try/ finallyблоки) , как правило , поощрять конкретный явный, конкретный и императивный стиль программирования.
  • В первый день команда Go опубликовала коллекцию идиом Go, а позже также собрала комментарии, обсуждения кода и официальные сообщения в блогах, чтобы научить стилю Go и философии программирования.

Инструменты

В основной дистрибутив Go входят инструменты для сборки , тестирования и анализа кода:

  • go build, который создает двоичные файлы Go, используя только информацию из самих исходных файлов, без отдельных make-файлов
  • go test, для модульного тестирования и микробенчмарков
  • go fmt, для форматирования кода
  • go install, для получения и установки удаленных пакетов
  • go vet, статический анализатор, ищущий возможные ошибки в коде
  • go run, ярлык для создания и выполнения кода
  • godoc, для отображения документации или обслуживания ее через HTTP
  • gorename, для переименования переменных, функций и т. д. безопасным для типов способом
  • go generate, стандартный способ вызова генераторов кода

Он также включает поддержку профилирования и отладки , инструментарий времени выполнения (например, для отслеживания пауз при сборке мусора ) и тестер состояния гонки .

Экосистема сторонних инструментов дополняет стандартный дистрибутив, например gocode, который позволяет автозаполнение кода во многих текстовых редакторах, goimportsавтоматически добавляет / удаляет импорт пакетов по мере необходимости и errcheckобнаруживает код, который может непреднамеренно игнорировать ошибки.

Примеры

Привет, мир

package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

где «FMT» является пакет для отформатирован ввода / вывода , аналогично языка C входной C файл / вывода .

Параллелизм

Следующая простая программа демонстрирует возможности параллелизма в Go для реализации асинхронной программы. Он запускает два легких потока («горутины»): один ждет, пока пользователь наберет текст, а другой реализует тайм-аут. Оператор select ожидает, пока одна из этих горутин отправит сообщение в основную подпрограмму, и действует с первым поступившим сообщением (пример, адаптированный из книги Дэвида Чизнолла).

package main

import (
    "fmt"
    "time"
)

func readword(ch chan string) {
    fmt.Println("Type a word, then hit Enter.")
    var word string
    fmt.Scanf("%s", &word)
    ch <- word
}

func timeout(t chan bool) {
    time.Sleep(5 * time.Second)
    t <- false
}

func main() {
    t := make(chan bool)
    go timeout(t)

    ch := make(chan string)
    go readword(ch)

    select {
    case word := <-ch:
        fmt.Println("Received", word)
    case <-t:
        fmt.Println("Timeout.")
    }
}

Тестирование

Пакет тестирования обеспечивает поддержку автоматического тестирования пакетов go. Пример целевой функции:

func ExtractUsername(email string) string {
	at := strings.Index(email, "@")
	return email[:at]
}

Тестовый код (обратите внимание, что ключевое слово assert отсутствует в Go; тесты находятся в <filename> _test.go в том же пакете):

import (
    "testing"    
)

func TestExtractUsername(t *testing.T) {
	t.Run("withoutDot", func(t *testing.T) {
		username := ExtractUsername("r@google.com")
		if username != "r" {
			t.Fatalf("Got: %v\n", username)
		}
	})

	t.Run("withDot", func(t *testing.T) {
		username := ExtractUsername("jonh.smith@example.com")
		if username != "jonh.smith" {
			t.Fatalf("Got: %v\n", username)
		}
	})

}

Есть возможность запускать тесты параллельно.

Веб-приложение

Пакет net / http обеспечивает поддержку для создания веб-приложений.

В этом примере будет показано "Hello world!" при посещении localhost: 8080.

package main

import (
    "fmt"
    "log"
    "net/http"    
)

func helloFunc(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello world!")
}

func main() {
    http.HandleFunc("/", helloFunc)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Приложения

Некоторые известные приложения с открытым исходным кодом, написанные на Go, включают:

  • Caddy , веб-сервер HTTP / 2 с открытым исходным кодом и автоматической поддержкой HTTPS.
  • CockroachDB , открытая, отказоустойчивая, строго согласованная, масштабируемая база данных SQL.
  • Consul , программное обеспечение для обнаружения сервисов на основе DNS и обеспечения распределенного хранения, сегментации и конфигурации ключевых значений.
  • Docker , набор инструментов для развертывания контейнеров Linux
  • EdgeX , платформа с открытым исходным кодом , не зависящая от поставщика, размещенная на базе Linux Foundation , обеспечивающая общую основу для промышленных периферийных вычислений IoT.
  • Hugo , генератор статических сайтов
  • InfluxDB , база данных с открытым исходным кодом, специально предназначенная для обработки данных временных рядов с высокой доступностью и высокими требованиями к производительности.
  • Межпланетная файловая система , одноранговый гипермедийный протокол с адресацией по содержанию.
  • Juju , инструмент оркестровки сервисов от Canonical , упаковщиков Ubuntu Linux
  • Система управления контейнерами Kubernetes
  • lnd, реализация сети Bitcoin Lightning
  • Mattermost , система командного чата
  • NATS Messaging , система обмена сообщениями с открытым исходным кодом, в которой заложены основные принципы проектирования производительности, масштабируемости и простоты использования.
  • OpenShift , платформа облачных вычислений как услуга от Red Hat
  • Rclone , программа командной строки для управления файлами в облачном хранилище и других сервисах с высокой задержкой.
  • Snappy , менеджер пакетов для Ubuntu Touch, разработанный Canonical
  • Syncthing , клиент-серверное приложение для синхронизации файлов с открытым исходным кодом
  • Terraform , инструмент для предоставления нескольких облачных инфраструктур с открытым исходным кодом от HashiCorp
  • TiDB , с открытым исходным кодом, распределенных ПЗВП базы данных совместим с протоколом MySQL от PingCAP

Другие известные компании и сайты, использующие Go (как правило, вместе с другими языками, а не исключительно), включают:

  • Cacoo за рендеринг страницы пользовательской панели и микросервиса с использованием Go и gRPC.
  • Chango , рекламная компания с алгоритмической продажей , использует Go в своих системах ставок в реальном времени.
  • Cloud Foundry , платформа как услуга
  • Cloudflare , для их прокси-сервера с дельта-кодированием Railgun, их распределенной службы DNS, а также инструментов для криптографии, ведения журналов, потоковой обработки и доступа к сайтам SPDY.
  • Контейнер Linux (ранее CoreOS), операционная система на основе Linux, использующая контейнеры Docker и контейнеры rkt.
  • Couchbase , службы запросов и индексирования на сервере Couchbase
  • Dropbox , который перенес некоторые из своих критически важных компонентов с Python на Go
  • Ethereum , реализация go-ethereum блокчейна виртуальной машины Ethereum для криптовалюты Ether
  • Gitlab , а веб- DevOps жизненного цикла инструмента , который обеспечивает Git - репозиторий , вика , отслеживание проблем , непрерывная интеграцию , развертывание особенности трубопровода
  • Google , для многих проектов, в частности, включая сервер загрузки dl.google.com
  • Heroku , для Doozer, сервис блокировки
  • Hyperledger Fabric , корпоративный проект распределенного реестра с открытым исходным кодом.
  • MongoDB , инструменты для администрирования экземпляров MongoDB
  • Netflix за две части их серверной архитектуры
  • Nutanix , для множества микросервисов в своей корпоративной облачной ОС.
  • Plug.dj , интерактивный веб-сайт для потоковой передачи музыки в социальных сетях
  • SendGrid , служба доставки и управления транзакционной электронной почтой из Боулдера, штат Колорадо.
  • SoundCloud , для «десятков систем»
  • Splice для всего бэкенда (API и парсеры) их онлайн-платформы для совместной работы с музыкой.
  • ThoughtWorks , некоторые инструменты и приложения для непрерывной доставки и обмена мгновенными сообщениями (CoyIM)
  • Twitch , для их системы чата на основе IRC (перенесена с Python)
  • Uber , для обработки больших объемов геозонов -Ы запросов


См. Также связанный запрос к Викиданным .

Прием

Интерфейсная система и преднамеренное отсутствие наследования были высоко оценены Микеле Симионато, который сравнил эти характеристики с характеристиками Standard ML , назвав «позором, что ни один популярный язык не пошел по [этому] конкретному пути».

Дэйв Астелс из Engine Yard писал:

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

Go был назван языком программирования года индексом сообщества программистов TIOBE в первый год, 2009, за больший 12-месячный рост популярности (всего за 2 месяца после его введения в ноябре), чем любой другой язык в этом году. и к январю 2010 года занял 13-е место, обогнав такие известные языки, как Паскаль . К июню 2015 года его рейтинг опустился ниже 50-го места в рейтинге, став ниже, чем COBOL и Fortran . Но по состоянию на январь 2017 года его рейтинг поднялся до 13-го места, что свидетельствует о значительном росте популярности и принятия. Go был признан языком программирования TIOBE 2016 года.

Брюс Экель заявил:

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

Оценка языка и его реализации gc в 2011 году по сравнению с C ++ ( GCC ), Java и Scala инженером Google показала:

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

-  Р. Хундт

Оценка получила опровержение со стороны команды разработчиков Go. Ян Лэнс Тейлор, улучшивший код Go для статьи Хундта, не знал о намерении опубликовать свой код и говорит, что его версия «никогда не предназначалась для того, чтобы быть примером идиоматического или эффективного Go»; Затем Расс Кокс оптимизировал код Go, а также код C ++, и заставил код Go работать немного быстрее, чем C ++, и более чем на порядок быстрее, чем код в статье.

Спор по именованию

10 ноября 2009 года, в день общего выпуска языка, Фрэнсис МакКейб, разработчик Go! язык программирования (обратите внимание на восклицательный знак), запросил изменение названия языка Google, чтобы избежать путаницы с его языком, на разработку которого он потратил 10 лет. Маккейб выразил обеспокоенность тем, что «большой парень» в конечном итоге обрушится на него », и это беспокойство нашло отклик у более чем 120 разработчиков, которые прокомментировали официальную ветку проблем Google, говоря, что им следует изменить имя, а некоторые даже сказали, что проблема противоречит девизу Google: Не будь злом .

12 октября 2010 г. проблема была закрыта разработчиком Google Рассом Коксом (@rsc) с пользовательским статусом «Несчастный», сопровождаемым следующим комментарием:

«Есть много компьютерных продуктов и услуг под названием Go. За 11 месяцев, прошедших с момента нашего выпуска, произошло минимальное смешение двух языков».

Критика

Критики Go говорят, что:

  • Отсутствие параметрического полиморфизма для универсального программирования приводит к дублированию кода или небезопасным преобразованиям типов и многословию, нарушающему поток.
  • Нулевое значение Go в сочетании с отсутствием алгебраических типов приводит к трудностям при обработке сбоев и базовых случаев .
  • Go не допускает появления открывающей скобки на отдельной строке, что заставляет всех программистов Go использовать один и тот же стиль скобок.
  • Семантика файлов в стандартной библиотеке Go в значительной степени основана на семантике POSIX , и они плохо отображаются на платформе Windows . Обратите внимание, что эта проблема не является специфической для Go, но другие языки программирования решили ее с помощью четко определенных стандартных библиотек. Автор также утверждает, что простота Go является иллюзией и что для решения реальных проблем необходимо задействовать библиотеки с удивительно большими зависимостями, чтобы решить такую ​​простую задачу, как реализация монотонно увеличивающейся функции времени.

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

Смотрите также

Примечания

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

funkyprogrammer .uk / concurrency-in-go-programming-language /

дальнейшее чтение

внешние ссылки