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

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

Если мы итерируемся по слайсу так:

for i, v := range slice 

то в переменную v попадает копия слайса

Копия элемента слайса?

Есть разница в производительности между передачей параметра по ссылке и по значению (нет)

Будем использовать такую эталонную функцию:

// наш эталон производительности
var testInt64 int64

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

make([]T, 0, n)

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

Зато легко пропустить ошибку в стиле

newarr := make([]int, len(arr), 0) // кто-то перепутал параметры местами

newarr = append(newarr, 1) // теперь у нас в начале неожиданные нули

Uber Go Style Guide с вами не согласится. Если можно подсказать gc сколько нужно аллоцировать памяти, то лучше это сделать если важна эффективность. К таким конструкциям не сложно привыкнуть, но да, даже где-то в go блоге писали, что это частая ошибка - когда путают len с capacity

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

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

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

почему читаемость мнимая?

по вашему код

y := make([]int, 0, len(something))

читается также легко как и:

x := []int{}

Потому что для меня например это приведет к тому что я пойду проверять что там за массив something то есть эта строка кода меня пусть немного но отвлечет

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

Разница в передаче по указателю/значению начинается на структурах от 16 байт и выше (ниже - выгоднее передавать по значению по возможности) - тест в статье ничего не показывает.

Смотря как передавать

Если с утечкой в хип (пример, при вызове метода интерфейса, замыкания и тд), то пусть структура хоть 300 байт весит — всё равно лучше передать по значению. Есть еще дополнительные нюансы, но в целом правило такое: лучше всегда передавать по значению там, где это возможно. Так GC и latency скажут спасибо

Если структура гарантировано не утечёт в хип, то да, лучше по указателю если структура занимает от двух машинных слов

Какая-то пустоватая статья, содержит кучу давно известных вещей (про defer, context, make, не самую быструю библиотеку json) и некоторые голословные заявления...

  • Не указана версия go, на которой выполнялись бенчмарки.

  • Нет ссылки на репозиторий, чтобы перепроверить результаты.

  • В параграфе "Есть разница в производительности между передачей параметра по ссылке и по значению":

    • есть уверенность, что вызов функций не превратился в inline?

    • а где пример для большой структуры или массива?

  • В параграфе "Оптимизация итерации по массиву" нет примера итерации:

    • через индекс

    • через slice

    Кроме того, это не особо полезная информация, так как в коде редко можно встретить массив из структур. Скорее всего это будет сразу срез (slice).

Всем давно известно, что

крайне сомнительное утверждение

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

Вот тут начинается какая-то дичь. Стек в го по умолчанию фиксирован, обычно размером в 4МиБ, и расти из-за цикла самостоятельно не может, насколько мне известно. defer рассказывает gc в какой момент надо удалять элементы и тот видимо под капотом пихает это в динамический массив, то бишь в кучу, а не на стек. Ну и как обычно - рассказали как не надо, но не показали как надо.

Про стек в 4Мб тоже дичь

Промахнулся. Должно быть КиБ. 2 КиБ минимальный, 4 КиБ большой

1гб же размер стека в последних версиях

Есть разница в производительности между передачей параметра по ссылке и по значению (нет)

а если передавать тяжелую структуру?

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

Я не эксперт в том, что там компилятор Go может наколдовать, но мне видится так, что сами по себе вызовы BenchmarkDirect(), а потом еще и incDirect() помещают в стек свои адреса возврата и переключают адресацию локальных переменных на новые области стека. Так каким же образом тогда получается доступ к переменной testInt64, оставшейся в другой области видимости? Очевидно, только по ссылке/указателю. Что в общем-то и подтверждают результаты теста.

// наш эталон производительности
var testInt64 int64

func BenchmarkDirect(b *testing.B) {
	for i := 0; i < b.N; i++ {
		incDirect()
	}
}

func incDirect() {
	testInt64++
}

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

Публикации

Истории