Please open Telegram to view this post
VIEW IN TELEGRAM
go.dev
Go 1.24 Release Notes - The Go Programming Language
🔥10👏3❤1✍1👌1💅1
Ранее писал про новую директиву
Alan Donovan из Go team недавно сделал PR, в котором добавил в пакеты
Здесь выглядит симпатично, *НО* это сделал инженер из Go team, а какое качество будет у разработчиков сторонних библиотек?
В целом, я буду делать по старинке, через
Как мне кажется, лучше было бы через
//go:fix inline.Alan Donovan из Go team недавно сделал PR, в котором добавил в пакеты
ioutil и reflect эту директиву для некоторых функций.Здесь выглядит симпатично, *НО* это сделал инженер из Go team, а какое качество будет у разработчиков сторонних библиотек?
В целом, я буду делать по старинке, через
golangci-lint искать deprecated функции и руками буду править.Как мне кажется, лучше было бы через
go vet предупреждение сделать, а не править так исходный код.✍5🔥1💅1💘1👾1
Недавно вспоминал о своем докладе: "Почему Docker написан на Go", который я готовил год назад для подлодки.
В этом докладе вас ждет:
- 🕵️ Теория заговора
- 📅 История контейнеризации с 1979 года
- 💔 Почему K8s отказался от Docker (спойлер: не совсем отказался)
- 📑 Не совсем публичные слайды команды dotCloud (ex Docker, inc)
📺 Смотреть
P.S. Все еще актуально, как и год назад!👀
В этом докладе вас ждет:
- 🕵️ Теория заговора
- 📅 История контейнеризации с 1979 года
- 💔 Почему K8s отказался от Docker (спойлер: не совсем отказался)
- 📑 Не совсем публичные слайды команды dotCloud (ex Docker, inc)
P.S. Все еще актуально, как и год назад!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤5🥰2
Ранее говорил о
И вот в новой версии Go (1.25) уже не понадобится библиотека github.com/uber-go/automaxprocs, так как
Уже даже документация обновлена для
GOMAXPROCS и cgroup.И вот в новой версии Go (1.25) уже не понадобится библиотека github.com/uber-go/automaxprocs, так как
cgroup для GOMAXPROCS будет учитываться "из коробки".Уже даже документация обновлена для
master ветки.🔥10✍3❤2🍓1💅1
Я пропустил что в Go 1.22 добавили работу с относительно новой сущностью Linux
Зачем это в Linux?
Работа с
- Получаем
- Процесс умирает,
- ОС создает новый процесс, переиспользуя
- В итоге мы работаем с совершенно другим процессом.
Это причина уязвимостей: CVE-2019-6133, CVE-2019-15790... А так же причина одного из issue у Go .
Решение
В Linux 5.1 появился системный вызов
Дальше (вплоть до ядра 6.5) добавили и другие методы получения
Что в Go?
И уже в Go 1.23 в методах и функциях, которые относятся к процессу используется по возможности
pidfd.Зачем это в Linux?
Работа с
PID по сути всегда гонка: - Получаем
PID процесса (например, PID=100);- Процесс умирает,
- ОС создает новый процесс, переиспользуя
PID=100;- В итоге мы работаем с совершенно другим процессом.
Это причина уязвимостей: CVE-2019-6133, CVE-2019-15790... А так же причина одного из issue у Go .
Решение
В Linux 5.1 появился системный вызов
pidfd_open(pid_t pid, unsigned int flags). Он даёт ссылку на конкретный процесс, а не на PID, который может быть переиспользован. Дальше (вплоть до ядра 6.5) добавили и другие методы получения
pidfd.Что в Go?
И уже в Go 1.23 в методах и функциях, которые относятся к процессу используется по возможности
pidfd.🔥9👍4🍾2👨💻2😁1💅1
В последнее время довольно часто приходится работать напрямую с TCP/UDP, а иногда и по SSH.
В таких случаях особенно важно использовать connection pool и следить, чтобы соединение не "умерло" - - так мы избегаем накладных расходов на рукопожатие (особенно важно если в протоколе есть дополнительные "телодвижения").
Отлично в этом помогает библиотека от jackc -- puddle (автор, кстати, того же pgx).
Грубо говоря, это
Примеры использования вне README можно посмотреть в исходниках pgx (файл pgxpool/pool.go) и ch-go (файл chpool/conn.go).
Ну и небольшой пример из README:
В таких случаях особенно важно использовать connection pool и следить, чтобы соединение не "умерло" - - так мы избегаем накладных расходов на рукопожатие (особенно важно если в протоколе есть дополнительные "телодвижения").
Отлично в этом помогает библиотека от jackc -- puddle (автор, кстати, того же pgx).
Грубо говоря, это
sync.Pool{}, только не для памяти, а для ресурсов, причём с возможностью ограничить количество создаваемых экземпляров. Если лимит достигнут, попытка получить новый ресурс блокируется до появления свободного -- что помогает контролировать нагрузку и избегать перерасхода соединений.Примеры использования вне README можно посмотреть в исходниках pgx (файл pgxpool/pool.go) и ch-go (файл chpool/conn.go).
Ну и небольшой пример из README:
func main() {
constructor := func(context.Context) (net.Conn, error) {
return net.Dial("tcp", "127.0.0.1:8080")
}
destructor := func(value net.Conn) {
value.Close()
}
maxPoolSize := int32(10)
pool, err := puddle.NewPool(&puddle.Config[net.Conn]{Constructor: constructor, Destructor: destructor, MaxSize: maxPoolSize})
if err != nil {
log.Fatal(err)
}
// Acquire resource from the pool.
res, err := pool.Acquire(context.Background())
if err != nil {
log.Fatal(err)
}
// Use resource.
_, err = res.Value().Write([]byte{1})
if err != nil {
log.Fatal(err)
}
// Release when done.
res.Release()
}
👍9🔥7
Уххх!
В Go начали завозить
То есть, возможно, можно будет вызывать SIMD инструкции напрямую, прямо из Go кода.
Для теста можно подтянуть ветку через
Правда, пока что поддержка только для amd64, так что локально потыкать у меня не получится :(
Как только появится arm -- обязательно сделаю бенчмарки и поделюсь результатами.
Кратко о текущем состоянии -- в комментарии Cherry Mui: https://github.com/golang/go/issues/73787#issuecomment-3208178910
В Go начали завозить
intrinsics для SIMD.То есть, возможно, можно будет вызывать SIMD инструкции напрямую, прямо из Go кода.
Для теста можно подтянуть ветку через
gotip:go install golang.org/dl/gotip@latest # если ещё не установлено
gotip download dev.simd # собираем ветку dev.simd
Правда, пока что поддержка только для amd64, так что локально потыкать у меня не получится :(
Как только появится arm -- обязательно сделаю бенчмарки и поделюсь результатами.
Кратко о текущем состоянии -- в комментарии Cherry Mui: https://github.com/golang/go/issues/73787#issuecomment-3208178910
GitHub
simd/archsimd: architecture-specific SIMD intrinsics under a GOEXPERIMENT · Issue #73787 · golang/go
Update (02/11/2026): The AMD64 low-level SIMD package is now available in Go 1.26 under GOEXPERIMENT=simd. There were minor bug fixes since the RC2. We'll continue the development for Go 1.27 o...
🔥3❤1👏1🍓1💅1👾1
В Go завезли поддержку valgrind -- утилиты, которая может обнаруживать утечки памяти.
Это, конечно, круто, но зачем?
На этот вопрос ответил автор CL, а также security team lead в Golang -- Roland Bracewell Shoemaker.
Основная цель -- находить функции, которые выполняются не за константное время.
Тут у кого-то может возникнуть вопрос:
SECURITY team lead .
В криптографии очень важно, чтобы функции выполнялись за константное время.
Если передавать разные входные данные и замерять время выполнения, можно провести timing oracle attack.
Тривиальный и упрощённый пример:
Мы побайтово сравниваем два хеша и при первом несовпадении выходим из функции раньше.
Тогда атакующий может подбирать хеш, ориентируясь на время выполнения запроса:
если оно немного замедлилось -- значит, один символ уже верный.
Чтобы предотвратить это, нужно, чтобы доступ к памяти и ветвление кода были одинаковыми для всех входных данных.
Для проверки этого как раз и нужен valgrind -- он отслеживает, какие области памяти и регистры используются в каждой ветке исполнения.
Подробнее про использование valgrind в рамках поиска функции, которые выполняются не за константное время можно почитать тутрепозиторию аж 15 лет .
Это, конечно, круто, но зачем?
На этот вопрос ответил автор CL, а также security team lead в Golang -- Roland Bracewell Shoemaker.
Основная цель -- находить функции, которые выполняются не за константное время.
Тут у кого-то может возникнуть вопрос:
Зачем нам функции, которые работают за константное время? Разве мы не хотим, чтобы они выполнялись как можно быстрее?А тут стоит посмотреть на роль того, кто добавил CL
В криптографии очень важно, чтобы функции выполнялись за константное время.
Если передавать разные входные данные и замерять время выполнения, можно провести timing oracle attack.
Тривиальный и упрощённый пример:
Мы побайтово сравниваем два хеша и при первом несовпадении выходим из функции раньше.
Тогда атакующий может подбирать хеш, ориентируясь на время выполнения запроса:
если оно немного замедлилось -- значит, один символ уже верный.
Чтобы предотвратить это, нужно, чтобы доступ к памяти и ветвление кода были одинаковыми для всех входных данных.
Для проверки этого как раз и нужен valgrind -- он отслеживает, какие области памяти и регистры используются в каждой ветке исполнения.
Подробнее про использование valgrind в рамках поиска функции, которые выполняются не за константное время можно почитать тут
🔥9✍3👾2💅1
Telegram
Lasiar работает 💡
Я пропустил что в Go 1.22 добавили работу с относительно новой сущностью Linux pidfd.
Зачем это в Linux?
Работа с PID по сути всегда гонка:
- Получаем PID процесса (например, PID=100);
- Процесс умирает,
- ОС создает новый процесс, переиспользуя PID=100;…
Зачем это в Linux?
Работа с PID по сути всегда гонка:
- Получаем PID процесса (например, PID=100);
- Процесс умирает,
- ОС создает новый процесс, переиспользуя PID=100;…
https://t.me/LasiarAtWork/50
А вот и добавили возможность использование
А вот и добавили возможность использование
pidfd напрямую.cmd.Process.WithHandle(func(handle uintptr) {
// работа с дескриптором процесса.
}✍4🤓2🔥1💅1
TL;DR
Изменения пользователя и прав в
Docker использует файловые системы, c поддержкой
Одно такое дерево файлов в терминологии
Слои нельзя изменить, изменения записываются в новый слой.
Каждая инструкция в
И когда мы копируем файлы и потом через
Особенно больно, когда у нас много файлов или они тяжелые.
Для изменения атрибутов, приходится все копировать в новый слой.
Чтобы избежать этого можно сразу указать
Изменения пользователя и прав в
Dockerfile при копировании можно выполнить одной командой.
COPY [--chown=<user>:<group>] [--chmod=<perms> ...] <src> ... <dest>
Docker использует файловые системы, c поддержкой
Union mount -- накладывание одного дерева файлов на другой.Одно такое дерево файлов в терминологии
Docker называется слой (layer).Слои нельзя изменить, изменения записываются в новый слой.
Каждая инструкция в
Dockerfile создает отдельный слой.И когда мы копируем файлы и потом через
RUN меняем права или принадлежность файла, файлы полностью копируются ещё раз в новый слой, уже с обновлёнными атрибутами.Особенно больно, когда у нас много файлов или они тяжелые.
Для изменения атрибутов, приходится все копировать в новый слой.
Чтобы избежать этого можно сразу указать
--chown и/или--chmod при копировании.
┌─────────────────────────┐
│ Верхний слой │ ← Изменения прав (chmod/chown)
├─────────────────────────┤
│ Данные приложения │ ← COPY . /app
├─────────────────────────┤
│ Базовый образ (OS) │ ← FROM ubuntu/alpine/etc
└─────────────────────────┘
✍6👍3🥰2👾2❤1💅1
Потихоньку в стандартную библиотеку Go добавляют работу с generic.
В Go 1.26 добавили функцию
Релиз Go 1.18, где появились generic был 25 марта 2022 года, а уже через 10 дней появился issue, где предлагалось добавить generic функцию в пакет errors.
Только первоначально говорилось об изменении
В целом -- мне нравится.
Во-первых, это выглядит симпатично:
Во-вторых, это значительно быстрее:
Код бенчмарка: https://go.dev/play/p/AcQyInSlR7D
Результат:
В Go 1.26 добавили функцию
errors.AsType[E error](err error) (E, bool).Релиз Go 1.18, где появились generic был 25 марта 2022 года, а уже через 10 дней появился issue, где предлагалось добавить generic функцию в пакет errors.
Только первоначально говорилось об изменении
errors.As(), возможно из-за этого только спустя три года добавилась функция errors.AsType().В целом -- мне нравится.
Во-первых, это выглядит симпатично:
pathError, ok := errors.AsType[*fs.PathError](err)
Во-вторых, это значительно быстрее:
Код бенчмарка: https://go.dev/play/p/AcQyInSlR7D
Результат:
goos: darwin
goarch: arm64
pkg: test
cpu: Apple M4 Pro
│ as.txt │ as_type.txt │
│ sec/op │ sec/op vs base │
Errors-12 33.480n ± 1% 2.113n ± 1% -93.69% (p=0.000 n=20)
│ as.txt │ as_type.txt │
│ B/op │ B/op vs base │
Errors-12 8.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=20)
│ as.txt │ as_type.txt │
│ allocs/op │ allocs/op vs base │
Errors-12 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=20)
🔥4✍3💘2👍1💅1
https://t.me/LasiarAtWork/53
В Go 1.26 добавят реализацию SIMD для amd64.
При этом возможно этот пакет будет использоваться в green tea(новый GC, который будет включен по умолчанию в Go 1.26) , что должно ускорить добавление других архитектур в пакете simd.
В Go 1.26 добавят реализацию SIMD для amd64.
При этом возможно этот пакет будет использоваться в green tea
Telegram
Lasiar работает 💡
Уххх!
В Go начали завозить intrinsics для SIMD.
То есть, возможно, можно будет вызывать SIMD инструкции напрямую, прямо из Go кода.
Для теста можно подтянуть ветку через gotip:
go install golang.org/dl/gotip@latest # если ещё не установлено
gotip download…
В Go начали завозить intrinsics для SIMD.
То есть, возможно, можно будет вызывать SIMD инструкции напрямую, прямо из Go кода.
Для теста можно подтянуть ветку через gotip:
go install golang.org/dl/gotip@latest # если ещё не установлено
gotip download…
🔥5
Там Nvidia в ядре Linux готовят сетевую подсистему под
Скорость просто невероятная!
Думаю что это необоходимо для нейроных сетей.
Немного контекста:
Nvidia с 2020 года владеет компанией Mellanox, которая выпускает сетевое оборудование для HPC.
1600Gbps (8x200Gbps).Скорость просто невероятная!
Думаю что это необоходимо для нейроных сетей.
Немного контекста:
Nvidia с 2020 года владеет компанией Mellanox, которая выпускает сетевое оборудование для HPC.
🔥4❤2
Неожиданно для себя я узнал что в DNS можно передавать порт 🙂
Всё благодаря новому типу записи -- SVCB который появился пару лет назад и описан в RFC 9460.
Вообще в драфте он был достаточно давно, даже некоторые DNS клиенты/сервера уже реализовать начали опираясь на драфт.
Во-первых у нас не совем типичные запросы:
мы хотим обратиться к "foo://api.example.com:8443", из-за этого у нас должен быть запрос:
Во-вторых можно передавать дополнительную информацию:
Я локально поднял DNS сервер и указал там SVCB запись.
запрос:
ответ:
Можно так же заметить что передает не только порт, но:
- alpn Application-Layer Protocol Negotiation -- инфомрация про протоколы, чтоб сразу понимать по какому протоколу стоит подключиться;
- ipv4hint, ipv6hint -- ранее нужно было выполнить два DNS запроса A для IPv4 и AAAA для IPv6, а сейчас всё можно получить за один раз.
В целом DNS становится сложнее, но при этом -- мощнее.
С помощью SVCB можно экономить на RTT. Кажется, это действительно крутая штука.
Всё благодаря новому типу записи -- SVCB который появился пару лет назад и описан в RFC 9460.
Во-первых у нас не совем типичные запросы:
мы хотим обратиться к "foo://api.example.com:8443", из-за этого у нас должен быть запрос:
_8443._foo.api.example.comВо-вторых можно передавать дополнительную информацию:
Я локально поднял DNS сервер и указал там SVCB запись.
запрос:
kdig _443._https.svc.example.test @127.0.0.1
ответ:
;; ANSWER SECTION:
_443._https.svc.example.com. 3600 IN SVCB 1 . alpn="h2,http/1.1" port=8443 ipv4hint=192.168.0.42 ipv6hint=fe80::1805:8978:a257:cea7
Можно так же заметить что передает не только порт, но:
- alpn Application-Layer Protocol Negotiation -- инфомрация про протоколы, чтоб сразу понимать по какому протоколу стоит подключиться;
- ipv4hint, ipv6hint -- ранее нужно было выполнить два DNS запроса A для IPv4 и AAAA для IPv6, а сейчас всё можно получить за один раз.
В целом DNS становится сложнее, но при этом -- мощнее.
С помощью SVCB можно экономить на RTT. Кажется, это действительно крутая штука.
👍6🔥4❤2
в 1.26 кроме green tea есть еще интересная оптимизация связанная со слайсами:
В чем суть этой оптимизации:
В некоторых случаях аллоцировать слайс во время append(а) на стеке, а не в куче. Это снижает нагрузку на GC.
К примеру, типичный код:
Во время итерирования, когда возрастает capacity (1, 2, 4, 8... итерация) создается память, которая не нужна. Эта памяти будет зачищаться при работе GC.
И в связи с этим стараемся не нагружать GC, а аллоцировать эти мусорные объекты на стеке.
И уже перед выходом из функции помещаем слайс на heap.
Немного деталей:
Во время append(а) вызывается не
Перечень того, где может использоваться эта оптимизация перечислина в тестовом файле, (где указано growsliceNoAlias, growsliceBuf).
Links:
CL: go-review.googlesource.com
Более подробная информация как это работат: cmd/compile/internal/slice/slice.go
stack-allocation optimization
for the backing store of slices.
В чем суть этой оптимизации:
В некоторых случаях аллоцировать слайс во время append(а) на стеке, а не в куче. Это снижает нагрузку на GC.
К примеру, типичный код:
func f(n int) []int {
var r []int
for i := range n {
r = append(r, i)
}
return r
}
Во время итерирования, когда возрастает capacity (1, 2, 4, 8... итерация) создается память, которая не нужна. Эта памяти будет зачищаться при работе GC.
И в связи с этим стараемся не нагружать GC, а аллоцировать эти мусорные объекты на стеке.
И уже перед выходом из функции помещаем слайс на heap.
func f(n int) []int {
var r []int
for i := range n {
r = append(r, i)
}
r = move2heap(r) // Подставляется во время комплияции
return r
}
Немного деталей:
Во время append(а) вызывается не
growslice, а growsliceBuf, где буффер это поинтер на стэк (link).Перечень того, где может использоваться эта оптимизация перечислина в тестовом файле, (где указано growsliceNoAlias, growsliceBuf).
Links:
CL: go-review.googlesource.com
Более подробная информация как это работат: cmd/compile/internal/slice/slice.go
👍5🔥3👏2