TG Telegram Group Link
Channel: Go Update
Back to Bottom
Опросы в канале, да или нет?

Там ко мне пришли с рекламой с предложением разместить опрос. Я обычно никакие опросы никогда сам не прохожу (кроме Go Developer Survey), поэтому оставляю решение за аудиторией. Как проголосуете, так и будем делать.

П.С. Рекламы не будет. Точно. Не сейчас, не потом.
Размещаем сторонние опросы?
Final Results
64%
Да
36%
Нет
Опрос

Тут это, ребята из DevCrowd проводят исследование среди Go-разработчиков:

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

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

Пройти опрос можно тут.
proposal: math/rand/v2 — первый v2 пакет в стандартной библиотеке

Расс Кокс предлагает добавить в std новый пакет, который должен стать заменой существующему math/rand.

Его ключевые особенности:
— Уберут метод Rand.Read и функцию Read. Аргументируют тем, что использование псевдослучайных чисел для генерации последовательностей из байт это почти всегда плохая идея. Более того, очень часто IDE подхватывает math/rand.Read когда должен подхватить crypto/rand.Read.
— Уберут Source.Seed, Rand.Seed, и функцию Seed. Глобальный Seed и так deprecated начиная с Go 1.20, а Source.Seed, Rand.Seed подразумевают, что зерно всегда имеет тип int64, что не всех случаях так. Плюс отсутствие функции Seed приведет к тому, что общий генератор случайных чисел будет всегда проинициализирован самим Go. Это позволит безболезненно менять алгоритм генерации случайных чисел глобальными функциями, не ломая обратную совместимость.
— У Source интерфейса изменят сигнатуру метода с Int63() int64 на Uint64() uint64. По этой же причине уберут интерфейс Source64.
— Будут проведены различные оптимизации существующих методов.
— Добавят дженерик функцию аля rand.N[V Number](v V) которая позволит легче работать с своими типами. Как пример: rand.N(1*time.Minute) где возвращаемое не нужно будет приводить к time.Duration.
— Новая реализация Source — PCG-DXSM, генератор который и быстрее и занимает меньше памяти. Судя по предварительному API состояние генератора можно будет сохранять и восстанавливать из слайса байт.

Главная мотивация, кроме улучшения самого генератора, это показать как именно v2 пакеты должны в будущем выглядеть в стандартной библиотеке. Как с ними должен будет работать тулинг и средства документации. Расс утверждает, что это будет хорошая подготовка перед началом работы над возможными sync/v2 и encoding/json/v2. Во вторых v2 позволяют показать преемственность пакетов и тот факт, что это не дизайн API с нуля, а набор изменений оригинального дизайна, где каждое изменение имеет под собой большое число факторов в свою пользу.
Дайджест активных предложений и дискуссий Go Core Team:

- spec: add untyped builtin zero: почти принят, о нем можно почитать тут.
- proposal: time: stop requiring Timer/Ticker.Stop for prompt GC: облегчающее жизнь изменение. Теперь не нужно вызывать Stop у таймера, что-бы его собрал сборщик мусора до истечения этого самого таймера. А это значит код типо case <- time.After(time.Minute): больше не приводит к утечкам, которые заметны на нагруженных местах.
- proposal: testing: add identity function that forces evaluation for benchmarks: бенчмарки пытаются научить не оптимизировать код внутри самого цикла бенчмарка. Иначе результаты могут показывать совсем не то, что вы думаете.
- proposal: cmd/compile: add new range behind GOEXPERIMENT=range: range над кастомными функциями идет в main бранч и будет скрыт под флагом.
- maps: remove Keys and Values for Go 1.21: из будущего пакета maps удалили две функции которые позволяли получить слайс ключей и слайс значений. Аргументируют, что в 1.22 завезут итераторы и хотят красивые имена сохранить для них.
- maps: remove package for Go 1.21: а вот сам пакет мы убирать не будем, много в нем хорошего и кроме тех двух функций.

Полный список - тут.
Релиз Go 1.21

Вот и состоялся релиз новой версии Go. Кроме того, что указано здесь, у нас так-же появились:

- Довольной большой пакет slices: среди прочего содержит функции Min / Max, функцию сортировки и функцию поиска в сортированном слайсе. И больше не нужно писать страшные блоки вставки и удаления элементов из слайса.
- Пакет maps: по сравнению со слайсами как-то бедновато, но есть удобная функция копирования.
- Пакет cmp: содержит обьявление всех сравниваемых по порядку типов и две базовые функции для работы с ними. Нужно скорее для пакетов maps и slices, а так-же разработчикам библиотек с коллекциями.
- Profile-guide optimization (PGO - оптимизация основанная на данных профилировки) вышла из превью и теперь применяется всегда если присутствует файл default.pgo в директории main пакета. Говорят, что благодаря ей удалось ускорить компилятор примерно на 6%.
- Улучшение пакета context: теперь можно вешать функцию на отмену контекста (удобно когда вам нужно закрыть канал или прекратить чтение из сокета) и отвязать дочерний контекст от отмены родителя.
- При выводе очень глубоких стеков теперь показывают 50 самых верхних и 50 самых нижних фреймов (названий функции) вместо 100 самых верхних как это было ранее. Должно помочь с отладкой паник в рекурсивных функциях.
И снова про итераторы…

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

У нас появятся новый пакет iter и два новых типа: Seq[V any] и Seq2[K, V any] которые будут описывать итераторы. Общий тип просили в первом обсуждении итераторов.

У нас будет четкий стандарт именования функций которые возвращают итераторы.

Если итерация может провалится, правильным и идиоматичным типом итератора будет iter.Seq2[MyType, error]. Соответсвенно каждый шаг сможет сам проверить себя на ошибку.

Нам дадут функцию для преобразования наших pull итераторов в push: func iter.Pull(seq iter.Seq[K,V]) (func() (K, V), stop func()) которая возвращает функцию для получения следующего элемента из итератора и функцию для его остановки. Здесь Расс еще раз напоминает, что писать push итераторы проще, процесс подготовки к работе и очистки у них делается в рамках одного потока управления, а не в разных функциях. А чем проще, тем меньше шанс совершить ошибку.

‼️ И главное: нам сразу подвезут кучу обновлений пакетов: strings, bytes, regexp а так-же обновления недавних slices и maps. Самих новых функций там очень много, судя по всему Расс учел опыт добавления дженериков, когда новую фичу привезли, а вот изменений в стандартную библиотеку под нее не привезли. Так же нас ждет пакет xiter (правда пока в exp модуле) которые даст большое число операций над этими самыми итераторами. Да-да ваши любимые Map, Filter, Concat, Merge, Zip — все это там будет.

Сам proposal состоит из нескольких частей, там довольно много и подробно описано, поэтому если хотите вникнуть - рекомендую ознакомится с оригиналом. А сам релиз Go 1.22 похоже обещает быть не менее интересным чем релиз Go 1.18. Ждем…
Короче теперь мы Java. Можно ынтыпрайз пилить.
Персональная запись: сегодня мне исполнился 31 год.

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

Идея вести такой список заметок по Go родилась спонтанно. Я довольно часто скидывал в чатики инфу про новые фичи или интересные, на мой взгляд, обсуждения в сообществе. Предложения от разработчиков языка, предложения от сообщества, тренд общей эволюции языка и свои, не редко критичные, мысли по этому поводу. Обьяснения зачем эти нововведения вообще нужны. После одного из таких сообщений, Коля Тузов (@justskiv) предложил мне начать вести блог, куда я буду структурированно это все писать. Структурированно требует сил и времени, это не напишешь в двух словах ибо нужно попытаться развить и обьяснить свою мысль. По этой причине я изначально отказывался.

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

Из других изменений: я недавно побывал в Чили. Про этот опыт мы скорее всего будем делать подкаст с Колей, вместе с обуждением работы над опенсорс проектом в распределенной команде — там есть о чем рассказать и подумать, как для тех кто думает о релокации, так и для тех кто считает что Латинская Америка это «апельсины, анаконда и амазонка».

Вообще отслеживание изменений это очень интересная штука. Когда я создавал этот канал, я думал тут будет максимум 100 подписчиков, так как тема довольно специфична. Как мне казалось большинству разработчиков вообще все равно, что там под капотом и куда движется сам язык (моя личная боль на собеседованиях). Однако нас уже больше 800 и восходящий тренд, судя по всему, не собирается останавливаться. За что отдельное спасибо всем и каждому из вас: если кто-то из вас узнал что-то новое для себя из моих записок, значит это все было не зря.

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

А в заключении вот что: такая запись это исключение. Моей изначальной идеей был и остается строго технический канал который охватывает ядро языка и небольшую часть экосистемы вокруг. Уже существует достаточно каналов которые рассказывают про новые библиотеки или крутые истории от пользователей языка. А вести блог про свои мысли о реальности в целом я бы наверное не стал: уже и так есть большое число людей, которые транслируют поток своего мозга в интернет 24/7.

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

И конечно же: Show must go on…
📝 Изменение формата имени версий Go начиная с Go 1.21

Начиная с Go 1.21 любая версия Go теперь всегда именуется как Go x.yy.zz взамен старого формата x.yy[.zz] где .zz не применялось для первого релиза внутри версии.

Проще всего понять на примерах:
→ Ранее Go 1.20 был и именем версии языка и именем первого релиза в ней. Т.е. для первого релиза go version возвращал go version go1.20 linux/amd64 для второго релиза go version go1.20.1 linux/amd64 и так далее.
→ Начиная с Go 1.21 это только имя версии языка. Первый релиз в этой версии называется 1.21.0. Т.е. для первого релиза go version возвращает go version go1.21.0 linux/amd64 для второго релиза go version go1.21.1 linux/amd64 и так далее.

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

А важно это по одной простой причине:
- Для первого релиза Go 1.20 была ссылка на скачивание https://storage.googleapis.com/golang/go1.20.linux-amd64.tar.gz
- Для первого релиза Go 1.21 ссылка на скачивание стала https://storage.googleapis.com/golang/go1.21.0.linux-amd64.tar.gz а старый формат ссылки выдаст 404.

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

Ссылка на общий чат.
🟢 Быстрая установка нужной версии компилятора Go без замены текущей.

Раз пошло обсуждение о том, как установить Go 1.21 не удаляя старую (и без менеджеров пакетов) — на самом деле все довольно просто:

$ go install golang.org/dl/go1.21.0@latest
$ go1.21.0 download

$ go1.21.0 run main.go

Для текущего мастера:

$ go install golang.org/dl/gotip@latest
$ gotip download

$ gotip run main.go

Полный список https://pkg.go.dev/golang.org/dl - там есть версии Go до 1.5 включительно.

gotip кстати умный - ему можно скормить бранч через gotip download BRANCHNAME или конкретный CL (PR) через gotip download CL-NUMBER. Номер всегда видно в конкретном ревью - например для https://go-review.googlesource.com/c/tools/+/518376/ комманда будет gotip download 518376.

Вот так легко можно поиграться с фичами Go которые еще находятся в разработке.
Go Update pinned «🟢 Быстрая установка нужной версии компилятора Go без замены текущей. Раз пошло обсуждение о том, как установить Go 1.21 не удаляя старую (и без менеджеров пакетов) — на самом деле все довольно просто: $ go install golang.org/dl/go1.21.0@latest $ go1.21.0…»
Улучшенный эскейп анализ для слайсов байт полученных из строк.

Из маленького, но приятного: наконец решили и закрыли одну из четырехзначных задач (сие значит очень старая задача, скорее всего еще из старого трекера) - #2205 read-only escape analysis and avoiding string -> []byte copies.

Допустим у вас есть код:

package main

import (
"strings"
"testing"
)

var Index int

func BenchmarkStrToSlice(b *testing.B) {
someStr := strings.Repeat("HELLO WORLD", 6)

for i := 0; i < b.N; i++ {
Index = indexByte([]byte(someStr), 'D')
}
}

func indexByte(s []byte, c byte) int {
// Я про bytes.IndexByte(s, c) которая быстрее.
// Эта функция здесь находится для демонстрации.
for i, b := range s {
if b == c {
return i
}
}

return -1
}

Сейчас вызов go test -benchmem -bench . выдаст примерно такие результаты:

BenchmarkStrToSlice-10 46341886 22.75 ns/op 80 B/op 1 allocs/op

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

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

На gotip test -benchmem -bench . результаты обнадеживают:

BenchmarkStrToSlice-10 248279863. 4.707 ns/op 0 B/op 0 allocs/op

Никаких больше копий при конвертации из строки в слайс, если мы будем только читать из слайса.
cmp: add Or

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

Я уже говорил о том, что proposal о zero ждут авторы кода с дженериками? Так вот это тот самый случай: сейчас cmp.Or нельзя реализовать без использования констрейнта comparable на дженериках. Который, в свою очередь, не работает с любыми типами внутри которых есть несравниваемые поля - например слайсы. А разгадка проста: для сравнения с нулем/пустой переменной сейчас авторы дженерик кода вынуждены создавать пустую переменную и проводить сравнивание с ней. Что довольно сильно ограничивает список типов с которыми такой код может работать.

Ссылка для желающих поиграться на практике.
🐞reflect: Value.IsZero should report true for negative zero

Довольно интересный баг в реализации reflect.Value.IsZero который происходит из попытки ответить на вопрос: а что выведет вот такой код?

val := math.Copysign(0, -1) // Создаем float64(-0.0)
println(val == 0, reflect.ValueOf(val).IsZero())

В Go 1.20 и 1.21 ответ будет true false

Реализация обработки чисел с плавающей точкой внутри IsZero в версиях 1.21 и ниже вызывает функцию math.Float64bits и затем сравнивает результат с 0. Это верно для общего случая, но вот для числа -0 результат вызова этой функции будет совсем не 0. При этом Go компилятор корректно обрабатывает такое сравнение в обычном коде, что и приводит к разным результатам.

Баг уже исправлен и фикс будет включен в Go 1.22. Так как этот фикс приводит к изменению поведения его скорее всего не будет в багфиксах существующих релизов.

П.С: Про интересное скоро будет, мне пока чудовищно не хватает времени.
Про интересное: intern package proposal

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

Неофиты спросят: «а в чем проблема? Почему нельзя использовать обычный словарь под мьютексом?». И ведь правда, мы можем использовать тип map для хранения уникальных значений любых сравниваемых типов. По скорости, словарь из стандартной библиотеки, превзойдут только уж совсем специализированные словари, которые большинство писать никогда не будет. Однако у этого подхода есть один существенный, но критический вопрос: как удалять ключи которых больше нет в нашей системе?

В языках со сборщиком мусора, типо Java и C#, для решения этой проблемы есть специализированные типы (WeakHashMap, WeakSet) которые автоматически удаляют ключи, на которые никто больше не ссылается. Под капотом практически все они используют weak reference (слабая ссылка, если только она ссылается на переменную, то сборщик мусора имеет право собрать переменную). Однако разработчики компилятора Go активно сопротивляются внедрению слабых ссылок в язык. Причины тому разные, но основная мысль кроется в нежелании усложнять рантайм и сборщик мусора без «лишней» необходимости.

Однако если чему-то сопротивляться, это не значит, что в этом чем-то пропадет потребность. Модуль go4.org/intern содержит в себе реализацию такой системы дедупликации значений. Авторами этого пакета являются разработчики Tailscale, часть из которых либо являлись частью Go Core Team в прошлом, либо активно работали над Go компилятором извне. Сам модуль используется внутри inet.af/netaddr который, в свою очередь, тянут в том числе и большие проекты.

Недостаток у go4.org/intern один: написан он с очень большим процентом черной магии, часть из которой еще и сильно ненадежна. Настолько ненадежна, что создателям модуля пришлось сделать (и регулярно обновлять) дополнительный модуль go4.org/unsafe/assume-no-moving-gc единственная цель которого, это убедиться, что сборщик мусора в Go все еще не двигает объекты в памяти хипа.

Проблема стала настолько явной, что Михаэль Кнызэк (один из ключевых разработчиков рантайма Go) предложил решить проблему уже на уровне стандартной библиотеки. Дескать не дело это, что модуль от которого зависит примерно 0,1% всей экосистемы (что достаточно много), может работать только в текущей внутрянке Go. Да и на дженерики бы уже неплохо все перенести. Предложенное API достаточно простое: есть одна глобальная функция которая возвращает враппер вокруг переменной и гарантирует ее уникальность в памяти. Враппер же нужен для быстрого сравнения уникальных значений между собой. А вся магия будет скрыта внутри райнтайма, который самостоятельно будет удалять переменные на которых больше никто не ссылается.

На мой взгляд, это попытка в очередной раз отложить внедрение слабых ссылок, потребность в которых назрела и перезрела уже давно. Однако меня устроит и такой вариант развития событий, ибо уже лучше чем ничего или магия которая может в любой момент развалиться.
Go Update
Update: proposal: spec: add untyped builtin zero Собрав фидбек Расс предлагает немного изменить правила использования для zero: новый идентификатор можно будет использовать для присваивания и сравнения только там где недоступны другие «короткие» идентификаторы…
proposal: spec: add untyped builtin zero (closed)

Случилось неожиданное. Предложение было принято. А затем собрав фидбэк (среди которого высказался и Роб «наше все» Пайк) Расс принял решение отозвать предложенное изменение. И хотя с самим отзывом я в корне не согласен, я могу понять причины: «срач» в ветке не утихал ни на день, породил два контр-предложения и вызывал новые проблемы в объяснении Go механик новичкам.

Однако сам факт отзыва расстроил меня под двум причинам:
- После принятия предложения и нескольких страниц срача, Расс обьявил, что в отсутствии новой информации, решение о принятии изменено не будет. А затем спустя несколько дней, в течении которых срач все равно продолжился, предложение было отозвано без каких либо комментариев. Что подводит к неприятной мысли о том, что любое предложение можно заставить отозвать просто через продолжение спора в обсуждении.
- Go Core Team явно имело внутренние разговоры по этому вопросу, однако поделится ими они не посчитали нужным. На мой взгляд, сие идет против духа открытого ПО. Но так как по факту Go полностью владеет Google, то и Open Source у нас очень условный.

Итог: на одно изменение меньше в Go 1.22. Возможно это и к лучшему…
И немного позитива: sync: add Map.Clear method

Там верно заметили, что раз у нас теперь есть встроенная функция clear для очистки словарей и слайсов, то хорошо бы такое иметь для sync.Map. Разработчики Go согласились и предложение было принято без лишних слов. Ждем реализации в Go 1.22.
📝 Где посмотреть список изменений в будущем релизе.

Список изменений на следующий релиз всегда доступен на https://tip.golang.org

Для Go 1.21 это был https://tip.golang.org/doc/go1.21
Для Go 1.22 это есть https://tip.golang.org/doc/go1.22
Для Go 1.23 это будет https://tip.golang.org/doc/go1.23

Однако сама страничка появляется примерно на второй-третий месяц разработки версии, а настоящая актуализация данных начинается за месяц-два до самого релиза. Т.е. сейчас на страничке 1.22 еще многого нет из того, что точно попадет в релиз.
HTML Embed Code:
2025/07/04 22:47:12
Back to Top