Примечания к выпуску 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, теперь заключает значения в двойные кавычки,
если значение содержит пробел или запятую.
Изменения на стороне сервера:
-
ServeMuxтеперь игнорирует порты в заголовке хоста при сопоставлении обработчиков. Хост сопоставляется без изменений для запросовCONNECT. -
Новый метод
Server.ServeTLSоборачиваетServer.Serve, добавляя поддержку TLS. -
Server.WriteTimeoutтеперь применяется к соединениям HTTP/2 и проверяется на уровне потока. - HTTP/2 теперь использует планировщик записи с приоритетами по умолчанию. Фреймы планируются с учётом приоритетов HTTP/2, описанных в RFC 7540 Section 5.3.
-
Обработчик HTTP, возвращаемый
StripPrefix, теперь вызывает предоставленный обработчик с модифицированной копией оригинального*http.Request. Любой код, который хранит состояние запроса в картах с ключами типа*http.Request, должен использоватьRequest.Context,Request.WithContextиcontext.WithValueвместо этого. -
LocalAddrContextKeyтеперь содержит фактический сетевой адрес соединения вместо адреса интерфейса, используемого слушером.
Изменения клиента и транспорта:
-
Transportтеперь поддерживает выполнение запросов через SOCKS5-прокси, если URL, возвращаемыйTransport.Proxy, имеет схемуsocks5.
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. Как и всегда, она используется только в том случае, если система ещё не имеет доступной базы данных.