Как стать автором
Обновить

Комментарии 12

Насчет передачи структур по ссылке ерунда имхо (в случае, который приведен в примере). Это точно не ошибка.

Примерно треть замечаний имеет отрицательную обратную сторону при бездумном применении: так, к примеру, функция имеющая внутри себя defer никогда не будет заинлайнена. Казалось бы "мелочь", но это приводит к избыточному дроблению, а вызов в Го - очень дорогое удовольствие, т.к. сперва вызывается "преамбула", которая в частности может увеличить размер стека, что может привести к неявной аллокации и "странному" поведению. Не все ошибки имеет смысл обрабатывать, так к примеру, число вытащенное из поля БД "int" при получении результата в виде строки (например складывали сами же в джейсон, или нам удобно получить это в джейсоне пачкой) при преобразовании в int проверять ошибку .. э-э-э зачем? Оно НЕ числом быть не может "по определению" (разного рода парсеры, кодеры/декодеры). Ну и т.д. Очень спорно многое, но как рекомендация джунам - сойдет. Если уж так хочется, то правильнее писать: num,_ := strconv.Atoi(numString) явно показывая, что обработка ошибки тут - избыточна.

Да, согласен, про обработку ошибок, это прямо очень простой уровень.

Да. Гораздо менее очевидно, что цикл с обходом мапы создает "генератор" с .. копированием, что влияет на его скорость..

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

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

Проверяли сами?

  1. Компилятор не инлайнит большинство "очевидных" мест, где подобное возможно. В частности, так любимые однократно вызываемые функции, создаваемые "по рекомендациям и петтернам".. фигушки. Если функция больше 80 (вроде подрастили) попугаев, то она НЕ инлайнится. Функции с дефером (даже одним) не инлайнятся, даже если там всего 3 строки. Методы как правило не инлайнятся, особенно если они часть интерфейса. Интерфейс вообще очень многое в методе перелопачивает в худшую сторону: в частности параметры в кучу - "только в путь"!

  2. Параметр, даже если не указатель .. легко может перетечь в кучу, особенно если Вы его передаете .. в интерфейсный метод. Упс.. неожиданно, правда?

  3. Да и сам стек .. он вообще-то создается в куче, кроме как в ветке main().. А ещё преамбула вызова далеко не бесплатна.. она среди прочего (копирование значений) ещё проверяет а не пора ли расширит стек? .. при каждом вызове.. (привет энтерпрайз!)

  4. Копии со стека (это вам кажется, что оно на стеке) часто (насчитывал 21 место в "оптимизаторе") переносится в кучу.

_, err := ioutil.ReadFile("config.json")

Наверное, имелось ввиду data, _ := ioutil.ReadFile("config.json")?

спасибо

и наверно нужно начать с того что:
- ioutil.ReadFile: Deprecated: As of Go 1.16, this function simply calls os

Неправильно:

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() 
}

Окей

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации