Pull to refresh
139
0
Искандер @quasilyte

https://www.quasilyte.dev/ebiten/ru/

Send message

Нет, в нём нет интеграций, да и сами утилиты совсем недавно появились.
Меня терзают некоторые сомнения насчёт запуска go-consistent вместе с другими проверками.


Лично я это писал для переодических уборок в коде, а не для постоянных проверок. Если на каждом ревью к такому придираться, может быть больше вреда, чем пользы. А править предупреждения go-consistent можно и автоматически, возможно сделаю даже флаг автоматического исправления, оно не должно ничего ломать, там как все альтернативы польностью эквивалентны (по крайней мере должны быть таковыми).

Если брать в расчёт стандартную библиотеку и произвольные функции, которые могут выполнять одинаковые операции, список будет стремиться к бесконечности. :)


Обычно в строку всё же через string(b) приводят, линтеры типа gosimple на некоторые схожие конструкции предлагают более простые замены.


go-consistent скорее о тех случаях, когда не очевидно, какой из вариантов "правильный", поэтому ответ ищется внутри исходных кодов проекта.

По-моему оптимизирование путём удаления "оптимизаций" — это просто прекрасно.


История с bytes.Buffer примерно такая же.
Улучшения получилось достигнуть с помощью удаления small buffer оптимизации:
https://go-review.googlesource.com/c/go/+/133715

Внезапно для себя обнаружил обсуждение на reddit.
https://www.reddit.com/r/golang/comments/9d5cp9/intelgobytebuf_replacement_for_bytesbuffer_that/


Внимание стоит обратить на disclaimer в bytebuf пакете. Это больше эксперимент, который позволил немного сдвинуться с мёртвой точки. В ближайшем времени могут появиться улучшения в стандартном bytes.Buffer (без изменений API, разумеется).

А почему не на Rust, например?
Почему именно C?

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

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

Но, если честно, это похоже на толстый троллинг.

(P.S. минусы вам не я поставил, но такую реакцию можно было ожидать, думаю, вы знали, на что идёте.)
> Кто то пишет в здравом уме на Го?

Почему бы и нет?

А к чему этот комментарий? Если это шутка, то не очень смешная, а если это всерьёз, то я не понимаю, откуда такая категоричность.

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


buf += fmt.Sprintf(" %d", val)

А если buf имеет алиасы? В Go строки не копируются при присваивании. Но вообще да, можно статически вывести безопасные случаи, когда buf гарантированно можно перезаписать.


s3 = s1 + S()

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


то у нас выделяется память под s3 и туда копируется и s1, и s2. Хотя, если бы мы при выделении памяти под s1 зарезервировали в конце достаточно места, до было бы достаточно скопировать только s2 в конец s1, чтобы получить s3

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


Ну, есть способы, конечно (например strconv.AppendInt() вместо += strconv.Itoa(), но они заставляют программиста опускаться к деталям реализации, вместо того чтобы переложить эту работу по оптимизации на компилятор.

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

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

Для выражения x + y + z + ... буффер выделяется единожды. А вот как копировать только правую часть я не понял. У нас же должна новая строка в результате получиться, при этом ни один из операндов не должен изменяться.


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

Не уверен, что понимаю, как это может быть возможно.


Вообще + не так часто используется в самых горячих участках. Если конкатенация нетривиальная и нам нужно больше 2-3 сложений, то лучше использовать какой-нибудь bytes.Buffer или strings.Builder.


Эх, мечты, мечты… ))

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

Хорошее замечание. Сейчас добавлю.

Понимаю ваше недоумение.


Но фукнция IsExported(s) проверяет лишь то, что переданная ей строка начинается с заглавной буквы. Метод VisitLocalDef() вызывается только для локальных определений,
поэтому если мы уже внутри и IsExported(s) вернул true, то это локальная переменная, которая начинается с заглавное буквы, что не имеет особого смысла, потому что это не влияет на семантику.

А в англоязычном Golang community есть канал #performance. :)
https://gophers.slack.com

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


Если у кого-то HPC может стать на 30% быстрее, то это не настолько весомый аргумент, потому что всё равно будет медленнее, чем на некоторых других языках.


Если же каким-то образом из-за этого компилятор станет быстрее за счёт более оптимального его же кода, процентов на 5, то вот на это волосы сообщества будут резонировать.

Самый честный ответ: никак. Все оптимизации локальны для одной функции.


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


  • Встраивание не только листовых функций (сейчас оно доступно, но не включено по умолчанию).
  • Улучшение cost модели для принятия решений о встраиваемости функций (cmd/compile: improve inlining cost model).

Возможно если бы кто-то показал, что глобальная оптимизация Go программ имеет эти свойства:


  1. Может быть реализована без значительного замедления компиляции.
  2. Значительно ускоряет программы, которые чувствительны к производительности.

То со временем это бы вливали в мастер. Сначала в виде эксперимента, потом в виде поведения по умолчанию, если бы не было значительных недостатков.

Новая оптимизация — это раздувание кодовой базы, усложнение проекта.

Да, но для новых SSA правил обычно порог принятия довольно низок. Если выглядит полезным — вливают. Уровень усложнения кодовой базы считается невысоким.


А нет ли какого-то правила, определяющего, можно ли добавлять данную оптимизацию в компилятор?

Каждый коммит в компилятор рекомендуется сопровождать бенчмарками и, если релевантно, статистикой изменения размера бинарников (тут помогают утилиты benchstat и bincmp). Самой ленивой проверкой является запуск ./make.bash с подсчётом срабатываний нового правила.


Если оптимизация именно на Go дистрибутиве не очень срабатывает, но выглядит полезной, стоит найти другой проект, где она срабатывает и даёт измеримый прирост.


Чем больше аргументов и статистики на руках — тем лучше.


При генерации кода из Rules можно передать параметр -log:


flag.Bool("log", false, "generate code that logs; for debugging only")

Тогда при ./make.bash (и вообще любом компилировании) будут подсчитываться все срабатывания правил. Только осторожно, там между запусками будет append в файл, так что он может до нескольких гигабайт вырасти достаточно незаметно; не забудьте выключить. :)

paramTypeCombine

В ней присутствуют false positive срабатывания для безымянных параметров. Если бы их не было, всё равно был бы вредным?


И если вы хотите иметь opinionated проверки

В недавнем обновлении по умолчанию experimental и opinionated выключены из -enable=all. В идеале eventually придём к более-менее нормальному default набору, но в качестве интеграции куда-то всё равно лучше явный список использовать.


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

Уже в golangci-lint добавиться планируем, там есть интеграции в том числе с редакторами. В gometalinter, наверное, тоже можно. Для проекта эти интеграции важны, согласен полностью.

Есть общепризнанный и лаконичный аналог на Русском, или только полная форма «статический анализатор»? Возможно, «анализатор» был бы уместным компромиссом.

В Лондоне, кстати, совсем скоро будет workshop:
https://www.meetup.com/Go-London-User-Group/events/251046966/
Организует упомянутый в статье Daniel Martí.


В англоязычном слаке (https://gophers.slack.com) есть канал contributor-workshop, где он предложил нам разместиться при следующем проведении. Из плюсов: там очень много людей из "Go core team".

Если у нас больше регистров, нужно меньше spill'ов в память, если в функции можно обойтись без «локальных слотов» внутри фрейма, фрейм у функции будет меньше или вообще нулевой, тогда при вызовах функции стек будет расти медленнее. Меньше стеки — меньше потребление памяти. Вот это имел в виду выше.

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

Можем закрыть эту тему?
Я не понимаю ваших мотивов и того, чего вы хотите.
Очевидно, мои ответы вам не помогают/не нравятся.
Go в том числе в датацентрах используется, а там есть понятие tail latency.

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

Хуже от того, что Go будет становиться более быстрым и/или потреблять меньше памяти, никому не будет.

Information

Rating
Does not participate
Location
Грузия
Registered
Activity