Примечания к выпуску Go 1.9

Введение в Go 1.9

Последний выпуск Go, версия 1.9, появился через шесть месяцев после Go 1.8 и является десятым выпуском в серии Go 1.x. Имеются два изменения в языке: добавление поддержки псевдонимов типов и определение условий, при которых реализации могут объединять операции с плавающей точкой. Большинство изменений касаются реализации инструментария, среды выполнения и библиотек. Как и всегда, выпуск сохраняет обещание совместимости Go 1. Ожидается, что почти все программы на Go будут продолжать компилироваться и выполняться так же, как и раньше.

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

Изменения в языке

Имеются два изменения в языке.

Go теперь поддерживает псевдонимы типов для поддержки постепенного исправления кода при перемещении типа между пакетами. Документ проектирования псевдонимов типов и статья о рефакторинге подробно рассматривают данную проблему. Кратко говоря, объявление псевдонима типа имеет следующий вид:

<code>type T1 = T2
</code>

Это объявление вводит псевдоним T1—альтернативное написание для типа, обозначаемого T2; то есть, оба T1 и T2 обозначают один и тот же тип.

Меньшее изменение в языке заключается в том, что спецификация языка теперь указывает, когда реализации могут объединять операции с плавающей точкой, например, используя инструкцию архитектуры “fused multiply and add” (FMA) для вычисления x*y + z без промежуточного округления результата x*y. Чтобы принудительно выполнить промежуточное округление, следует написать float64(x*y) + z.

Платформы

В этом выпуске нет новых поддерживаемых операционных систем или архитектур процессоров.

ppc64x требуют POWER8

Оба GOARCH=ppc64 и GOARCH=ppc64le теперь требуют поддержки хотя бы POWER8. В предыдущих выпусках, только GOARCH=ppc64le требовал POWER8, а архитектура big endian ppc64 поддерживала более старое оборудование.

FreeBSD

Go 1.9 — последний выпуск, который может работать на FreeBSD 9.3, что уже не поддерживается FreeBSD. Go 1.10 будет требовать FreeBSD 10.3+.

OpenBSD 6.0

Go 1.9 теперь включает генерацию PT_TLS для двоичных файлов cgo и, соответственно, требует OpenBSD 6.0 или новее. Go 1.9 больше не поддерживает OpenBSD 5.9.

Известные проблемы

Существуют некоторые нестабильности на FreeBSD, которые известны, но пока не поняты. Это может привести к сбоям в редких случаях. См. issue 15658. Любая помощь в решении этой проблемы, специфичной для FreeBSD, будет признана.

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

Инструменты

Параллельная компиляция

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

Сопоставление с ./… в vendor

По запросам пользователей, ./... больше не сопоставляет пакеты в каталогах vendor в инструментах, принимающих имена пакетов, например, go test. Чтобы сопоставить каталоги vendor, нужно указать ./vendor/....

Перемещённый GOROOT

Инструмент go теперь будет использовать путь, с которого он был вызван, чтобы попытаться найти корневой каталог установки Go. Это означает, что если вся установка Go будет перемещена в новое место, инструмент go должен продолжать работать обычным образом. Это поведение может быть переопределено установкой GOROOT в переменной окружения, что следует делать только в необычных обстоятельствах. Обратите внимание, что это не влияет на результат функции runtime.GOROOT, которая будет продолжать сообщать исходное местоположение установки; это может быть исправлено в будущих релизах.

Инструментарий компилятора

Деление комплексных чисел теперь совместимо с C99. Это всегда было так в gccgo и теперь исправлено в инструментарии gc.

Линкер теперь будет генерировать информацию DWARF для исполняемых файлов cgo в Windows.

Компилятор теперь включает лексические области видимости в сгенерированную DWARF, если переданы флаги -N -l, что позволяет отладчикам скрывать переменные, которые не находятся в области видимости. Раздел .debug_info теперь соответствует версии DWARF 4.

Значения GOARM и GO386 теперь влияют на ID сборки скомпилированного пакета, используемого кэшированием зависимостей инструментом go.

Ассемблер

Четырехоперандная инструкция ARM MULA теперь корректно ассемблируется, при этом регистр слагаемого передаётся как третий аргумент, а регистр результата — как четвёртый и последний аргумент. В предыдущих версиях эти значения были перевёрнуты. Трёхоперандная форма, в которой четвёртый аргумент неявно совпадает с третьим, остаётся неизменной. Код, использующий четырёхоперандные инструкции MULA, потребует обновления, однако мы полагаем, что эта форма применяется очень редко. Инструкции MULAWT и MULAWB уже использовали правильный порядок во всех формах и остаются неизменными.

Ассемблер теперь поддерживает ADDSUBPS/PD, тем самым завершая два отсутствующих инструкции x86 SSE3.

Doc

Длинные списки аргументов теперь обрезаются. Это улучшает читаемость команды go doc для некоторого сгенерированного кода.

Просмотр документации по полям структуры теперь поддерживается. Например, go doc http.Client.Jar.

Env

Новый флаг go env -json включает вывод в формате JSON, вместо формата вывода по умолчанию, зависящего от операционной системы.

Test

Команда go test принимает новый флаг -list, который принимает регулярное выражение в качестве аргумента и выводит в stdout имя любых тестов, бенчмарков или примеров, соответствующих ему, без их запуска.

Pprof

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

Команда go tool pprof теперь использует информацию о HTTP-прокси, определённую в переменных окружения, с использованием http.ProxyFromEnvironment.

Vet

Команда vet лучше интегрирована в go tool, так что go vet теперь поддерживает все стандартные флаги сборки, а флаги самого vet теперь доступны как из go vet, так и из go tool vet.

Gccgo

Из-за согласования полугодового релизного цикла Go с годовым циклом релизов GCC, в релизе GCC 7 содержится версия gccgo из Go 1.8.3. Ожидается, что следующий релиз, GCC 8, будет содержать версию gccgo из Go 1.10.

Среда выполнения

Стеки вызовов с встроенными фреймами

Пользователи runtime.Callers должны избегать прямого анализа полученного среза PC и вместо этого использовать runtime.CallersFrames для получения полного представления о стеке вызовов или runtime.Caller для получения информации о единственном вызывающем фрейме. Это связано с тем, что отдельный элемент среза PC не может учитывать встроенные фреймы или другие особенности стека вызовов.

В частности, код, который напрямую перебирает срез PC и использует функции, такие как runtime.FuncForPC для разрешения каждого PC по отдельности, будет упускать встроенные фреймы. Чтобы получить полное представление о стеке, такой код должен вместо этого использовать CallersFrames. Аналогично, код не должен полагаться на длину, возвращаемую функцией Callers, как на показатель глубины вызовов. Вместо этого следует подсчитать количество фреймов, возвращённых CallersFrames.

Код, который запрашивает информацию о единственном вызывающем на определённой глубине, должен использовать Caller, а не передавать срез длины 1 в Callers.

runtime.CallersFrames доступен начиная с Go 1.7, поэтому код может быть обновлён до этого момента, до перехода на Go 1.9.

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

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

Сборщик мусора

Функции библиотеки, ранее вызывавшие остановку мира (stop-the-world) сборку мусора, теперь запускают параллельную сборку мусора. Конкретно, runtime.GC, debug.SetGCPercent, и debug.FreeOSMemory, теперь запускают параллельную сборку мусора, блокируя только вызывающую горутину до завершения сборки мусора.

Функция debug.SetGCPercent вызывает сборку мусора только в случае немедленной необходимости из-за нового значения GOGC. Это позволяет динамически изменять GOGC.

Производительность выделения больших объектов значительно улучшена в приложениях с большими (>50 ГБ) кучами, содержащими множество больших объектов.

Функция runtime.ReadMemStats теперь выполняется за менее чем 100 мкс даже при очень больших кучах.

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

Прозрачная поддержка монотонного времени

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

Новый пакет для работы с битами

В Go 1.9 представлен новый пакет, math/bits, содержащий оптимизированные реализации для работы с битами. На большинстве архитектур функции этого пакета дополнительно распознаются компилятором и обрабатываются как встроенные функции для дополнительного повышения производительности.

Функции-помощники для тестирования

Новые методы (*T).Helper и (*B).Helper отмечают вызывающую функцию как функцию-помощник для тестирования. При выводе информации о файле и строке, эта функция будет пропущена. Это позволяет создавать функции-помощники для тестирования, сохраняя при этом полезные номера строк для пользователей.

Параллельная карта

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

Метки профайлера

Пакет runtime/pprof теперь поддерживает добавление меток к записям профайлера pprof. Метки формируют карту ключ-значение, которая используется для различения вызовов одной и той же функции в различных контекстах при анализе профилей с помощью команды pprof. Новая функция Do пакета pprof выполняет код, связанный с заданными метками. Также в пакете появились новые функции для работы с метками.

Незначительные изменения в библиотеке

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

archive/zip

ZIP Writer теперь устанавливает бит UTF-8 в поле FileHeader.Flags при соответствующем случае.

crypto/rand

В Linux Go теперь вызывает системный вызов getrandom без флага GRND_NONBLOCK; теперь выполнение будет блокироваться до тех пор, пока ядро не обеспечит достаточное количество случайных данных. В ядрах, не поддерживающих системный вызов getrandom, Go продолжает читать из /dev/urandom.

crypto/x509

В Unix-системах переменные окружения SSL_CERT_FILE и SSL_CERT_DIR теперь могут использоваться для переопределения стандартных местоположений файла сертификатов SSL и каталога файлов сертификатов SSL соответственно.

Файл FreeBSD /usr/local/etc/ssl/cert.pem теперь включён в путь поиска сертификатов.

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

Если в сертификате присутствует расширение SAN, включая случаи без имён DNS, то Common Name из Subject игнорируется. В предыдущих версиях код проверял только наличие DNS-имён в SAN сертификатов.

database/sql

Пакет теперь будет использовать кэшированный Stmt, если он доступен в Tx.Stmt. Это предотвращает повторную подготовку операторов каждый раз, когда вызывается Tx.Stmt.

Пакет теперь позволяет драйверам реализовывать собственные проверяющие функции аргументов, реализуя driver.NamedValueChecker. Это также позволяет драйверам поддерживать типы параметров OUTPUT и INOUT. Out должен использоваться для возврата выходных параметров, если это поддерживается драйвером.

Rows.Scan теперь может сканировать пользовательские строковые типы. Ранее пакет поддерживал сканирование в числовые типы, такие как type Int int64. Теперь также поддерживается сканирование в строковые типы, такие как type String string.

Новый метод DB.Conn возвращает новый Conn тип, представляющий эксклюзивное соединение с базой данных из пула соединений. Все запросы, выполняемые на Conn, будут использовать одно и то же базовое соединение до тех пор, пока не будет вызван метод Conn.Close, чтобы вернуть соединение обратно в пул соединений.

encoding/asn1

Новые NullBytes и NullRawValue представляют тип ASN.1 NULL.

encoding/base32

Новый метод Encoding.WithPadding добавляет поддержку пользовательских символов заполнения и отключения заполнения.

encoding/csv

Новое поле Reader.ReuseRecord управляет тем, могут ли вызовы Read возвращать срез, разделяющий массив базового элемента предыдущего вызова, для повышения производительности.

fmt

Флаг решётки (’#’) теперь поддерживается при печати вещественных и комплексных чисел. Он всегда будет выводить десятичную точку для %e, %E, %f, %F, %g и %G; он не будет удалять завершающие нули для %g и %G.

hash/fnv

Пакет теперь включает поддержку 128-битных хэшей FNV-1 и FNV-1a с помощью New128 и New128a, соответственно.

html/template

Пакет теперь сообщает об ошибке, если предопределённый экранировщик (один из «html», «urlquery» и «js») находится в конвейере и не соответствует тому, что автоэкранировщик решил бы сам. Это избегает определённых проблем безопасности или корректности. Теперь использование одного из этих экранировщиков всегда либо является ничего не делающим действием, либо ошибкой. (Случай ничего не делающего действия облегчает миграцию с text/template.)

image

Метод Rectangle.Intersect теперь возвращает нулевой Rectangle при вызове на смежных, но не пересекающихся прямоугольниках, как это описано в документации. В предыдущих версиях он неправильно возвращал пустой, но ненулевой Rectangle.

image/color

Формула преобразования YCbCr в RGBA была изменена для обеспечения того, чтобы корректировки округления охватывали полный диапазон [0, 0xffff] RGBA.

image/png

Новое поле Encoder.BufferPool позволяет указать EncoderBufferPool, который будет использоваться кодером для получения временных EncoderBuffer буферов при кодировании изображения PNG. Использование BufferPool уменьшает количество выделений памяти, выполняемых при кодировании нескольких изображений.

Пакет теперь поддерживает декодирование прозрачных 8-битных изображений в оттенках серого (“Gray8”).

math/big

Новые методы IsInt64 и IsUint64 сообщают, может ли значение типа Int быть представлено как значение типа int64 или uint64.

mime/multipart

Новое поле FileHeader.Size описывает размер файла в сообщении multipart.

net

Новое поле Resolver.StrictErrors обеспечивает контроль над тем, как встроенный DNS-резолвер Go обрабатывает временные ошибки во время запросов, состоящих из нескольких подзапросов, таких как поиск адресов A+AAAA.

Новый метод Resolver.Dial позволяет использовать пользовательскую функцию подключения для Resolver.

JoinHostPort теперь помещает адрес в квадратные скобки только в том случае, если хост содержит двоеточие. В предыдущих версиях адрес также оборачивался в квадратные скобки, если он содержал знак процента (’%’).

Новые методы TCPConn.SyscallConn, IPConn.SyscallConn, UDPConn.SyscallConn и UnixConn.SyscallConn обеспечивают доступ к базовым дескрипторам файлов соединений.

Теперь безопасно вызывать Dial с адресом, полученным из (*TCPListener).String(), после создания слушера с помощью Listen(“tcp”, “:0”). Ранее это вызывало ошибку на некоторых машинах с частично настроенной IPv6-инфраструктурой.

net/http

Метод Cookie.String, используемый для заголовков Cookie и Set-Cookie, теперь заключает значения в двойные кавычки, если значение содержит пробел или запятую.

Изменения на стороне сервера:

Изменения клиента и транспорта:

net/http/fcgi

Новая функция ProcessEnv возвращает переменные среды FastCGI, связанные с HTTP-запросом, для которого нет соответствующих полей в http.Request, например, REMOTE_USER.

net/http/httptest

Новый метод Server.Client возвращает HTTP-клиент, настроенный для выполнения запросов к тестовому серверу.

Новый метод Server.Certificate возвращает TLS-сертификат тестового сервера, если он имеется.

net/http/httputil

ReverseProxy теперь проксирует все HTTP/2 trailer'ы ответов, даже те, которые не были объявлены в начальном заголовке ответа. Такие необъявленные trailer'ы используются протоколом gRPC.

os

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

В Windows, Args теперь заполняется без использования shell32.dll, что улучшает время запуска процесса на 1–7 мс.

os/exec

Пакет os/exec теперь предотвращает создание дочерних процессов с любыми дублирующимися переменными среды. Если Cmd.Env содержит дублирующиеся ключи среды, используется только последнее значение в слайсе для каждого дублирующегося ключа.

os/user

Lookup и LookupId теперь работают в Unix-системах при CGO_ENABLED=0, читая файл /etc/passwd.

LookupGroup и LookupGroupId теперь работают в Unix-системах при CGO_ENABLED=0, читая файл /etc/group.

reflect

Новая функция MakeMapWithSize создаёт карту с подсказкой по вместимости.

runtime

Трассировки, генерируемые средой выполнения и записываемые в профили, теперь точны при наличии инлайна. Для получения трассировок программно приложения должны использовать runtime.CallersFrames вместо прямой итерации по результатам runtime.Callers.

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

В FreeBSD GOMAXPROCS и runtime.NumCPU теперь основаны на маске CPU процесса, а не на общем количестве CPU.

Среда выполнения имеет предварительную поддержку Android O.

runtime/debug

Вызов SetGCPercent с отрицательным значением больше не запускает немедленную сборку мусора.

runtime/trace

Трассировка выполнения теперь отображает события mark assist, которые указывают, когда горутина приложения вынуждена协助 сборке мусора из-за слишком быстрого выделения памяти.

События «sweep» теперь охватывают весь процесс поиска свободного пространства для выделения, а не записывают каждую отдельную span, которая была просканирована. Это снижает задержку при выделении памяти при трассировке программ, интенсивно использующих выделение. Событие sweep показывает, сколько байтов было просканировано и сколько было восстановлено.

sync

Mutex теперь более справедлив.

syscall

Новое поле Credential.NoSetGroups управляет тем, делает ли система Unix вызов setgroups для установки дополнительных групп при запуске нового процесса.

Новое поле SysProcAttr.AmbientCaps позволяет устанавливать амбиентные привилегии в Linux 4.3+ при создании нового процесса.

В 64-битной версии x86 Linux оптимизирована задержка создания процесса с использованием CLONE_VFORK и CLONE_VM.

Новый интерфейс Conn описывает некоторые типы в пакете net, которые могут предоставить доступ к их базовому дескриптору файла с помощью нового интерфейса RawConn.

testing/quick

Пакет теперь выбирает значения в полном диапазоне при генерации случайных чисел типа int64 и uint64; в предыдущих версиях сгенерированные значения всегда ограничивались диапазоном [-262, 262)

В предыдущих версиях использование нулевого значения Config.Rand приводило к использованию фиксированного детерминированного генератора случайных чисел. Теперь используется генератор случайных чисел, инициализированный текущим временем. Для получения старого поведения установите Config.Rand в rand.New(rand.NewSource(0)).

text/template

Обработка пустых блоков, которая была сломана изменением в Go 1.8, сделавшим результат зависимым от порядка шаблонов, была исправлена, восстановив поведение Go 1.7.

time

Новые методы Duration.Round и Duration.Truncate обрабатывают округление и усечение продолжительностей до кратных заданной продолжительности.

Получение времени и операция сна теперь работают корректно под Wine.

Если значение типа Time имеет чтение монотонных часов, его строковое представление (как возвращается методом String) теперь включает финальное поле "m=±value", где value — это чтение монотонных часов, отформатированное как десятичное число секунд.

Включённая база данных часовых поясов tzdata была обновлена до версии 2017b. Как и всегда, она используется только в том случае, если система ещё не имеет доступной базы данных.

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang