Комментарии 12
Насчет передачи структур по ссылке ерунда имхо (в случае, который приведен в примере). Это точно не ошибка.
Примерно треть замечаний имеет отрицательную обратную сторону при бездумном применении: так, к примеру, функция имеющая внутри себя defer никогда не будет заинлайнена. Казалось бы "мелочь", но это приводит к избыточному дроблению, а вызов в Го - очень дорогое удовольствие, т.к. сперва вызывается "преамбула", которая в частности может увеличить размер стека, что может привести к неявной аллокации и "странному" поведению. Не все ошибки имеет смысл обрабатывать, так к примеру, число вытащенное из поля БД "int" при получении результата в виде строки (например складывали сами же в джейсон, или нам удобно получить это в джейсоне пачкой) при преобразовании в int проверять ошибку .. э-э-э зачем? Оно НЕ числом быть не может "по определению" (разного рода парсеры, кодеры/декодеры). Ну и т.д. Очень спорно многое, но как рекомендация джунам - сойдет. Если уж так хочется, то правильнее писать: num,_ := strconv.Atoi(numString) явно показывая, что обработка ошибки тут - избыточна.
В данном случае это вообще не будет ошибкой, потому что компилятор спокойно заинлайнит функцию, а затем разыменует указатель так как в нем не будет необходимости после инлайна. Автор нарушил свой же пункт о преждевременной оптимизации.
Кстати даже если допустить, что функция не заинлайнится, то передача по значению чаще всего быстрее, так как создание копии на стеке как правило дешевле алокации в куче и сборки мусора. Копия на стеке дороже только в случае больших структур
Проверяли сами?
Компилятор не инлайнит большинство "очевидных" мест, где подобное возможно. В частности, так любимые однократно вызываемые функции, создаваемые "по рекомендациям и петтернам".. фигушки. Если функция больше 80 (вроде подрастили) попугаев, то она НЕ инлайнится. Функции с дефером (даже одним) не инлайнятся, даже если там всего 3 строки. Методы как правило не инлайнятся, особенно если они часть интерфейса. Интерфейс вообще очень многое в методе перелопачивает в худшую сторону: в частности параметры в кучу - "только в путь"!
Параметр, даже если не указатель .. легко может перетечь в кучу, особенно если Вы его передаете .. в интерфейсный метод. Упс.. неожиданно, правда?
Да и сам стек .. он вообще-то создается в куче, кроме как в ветке main().. А ещё преамбула вызова далеко не бесплатна.. она среди прочего (копирование значений) ещё проверяет а не пора ли расширит стек? .. при каждом вызове.. (привет энтерпрайз!)
Копии со стека (это вам кажется, что оно на стеке) часто (насчитывал 21 место в "оптимизаторе") переносится в кучу.
_, err := ioutil.ReadFile("config.json")
Наверное, имелось ввиду data, _ := ioutil.ReadFile("config.json")
?
Неправильно:
buf := make([]byte, 0, 1024)
Правильно:
buf := []byte{}
Первый вариант не сильно менее читабелен, чем второй, и при этом экономит аллокации.
Оптимизируйте только по необходимости и после профилирования.
Это приводит к тому, что откровенно тормозные места выявлены и исправлены с помощью профилировщика, а код всё равно медленный. Причем равномерно-медленный. Пойди, попробуй такой исправить, если у вас такого кода полмиллиона строк...
Не надо вставать на уши ради оптимизации, если нет понимания, что вот данное конкретное место тормозит. Но это не отменяет необходимости писать аккуратно всегда - в т.ч., не создавая "пессимизации" без нужды.
Передача структур по значению ухудшает производительность.
Это не такой простой вопрос. Передача структур по указателю (1) удорожает доступ к их полям (2) создаёт риск лишней аллокации, если гошный escape detector не сообразит, что аллокация в этом месте не нужна (или если окажется, что она правда нужна).
Кроме того, передавая структуры по указателю, вы открываете вызываемой функции не нужный, возможно, доступ на запись в эту структуру. К сожалению, в Go нет const ptr...
То самое место, где надо сначала профилировать, потом оптимизировать.
ахахах, а в fmt.Printf нет reflection?
func
print[T any](value T) { fmt.Printf("%v\n", value)}
package main
import (
"bufio"
"os"
"strconv"
)
var writer = bufio.NewWriterSize(os.Stdout, 4096)
func printString(s string) {
writer.WriteString(s)
writer.WriteByte('\n')
}
func printInt(i int) {
writer.WriteString(strconv.Itoa(i))
writer.WriteByte('\n')
}
func printBool(b bool) {
writer.WriteString(strconv.FormatBool(b))
writer.WriteByte('\n')
}
func flush() {
writer.Flush()
}
func main() {
printString("Hello, world!")
printInt(42)
printBool(true)
flush()
}
Окей
Golang Top 15 ошибок