Два трюка с кодом Go, которые могут повысить эффективность в тысячу раз

Go

http://dawngrp.com/gao-xiao-de-goyu-yan-bian-ma-ji-qiao/

1. Не используйте + и fmt.Sprintf для управления строками.

+Работа со строками очень удобна, но очень медленна. Использование + в языке Go заставит вашу программу работать больше, чем языки сценариев. 100 000 раз, Python, Javascript намного быстрее, чем Go (много, а не немного)

func TestStr(t *testing.T) {
	str := ""
	for i := 0; i < 100000; i++ {
    	str += "test"
	}
}

Результаты теста

PASS: TestStr (3.32s)

str=""
for i in range(100000):
    str+="test"

Результаты теста:

~/» time python test.py
0.03s user 0.03s system 81% cpu 0.078 total

Как статический язык, Go на самом деле в 100 раз медленнее, чем Python на таком простом фрагменте кода.Это невероятно, правда? Это не проблема Go, но использование + для обработки строк в Go очень требовательно к производительности, и Python должен иметь перегруженную оптимизацию для + операций со строками. (Javascript + манипулирование строками также быстро)

Самый эффективный способ - использовать буфер
strBuf := bytes.NewBufferString("")
for i := 0; i < 100000; i++ {
	strBuf.WriteString("test")
}

Результаты можно проверить самостоятельно и они вас удивят

Некоторым нужно просто объединить две строки. Использование Buffer немного хлопотно. Легче придумать для объединения использование fmt.Sprintf(). Исходный код во многих пакетах также написан таким образом. На самом деле, Sprintf fmt тоже очень медленный, если нет вывода сложного преобразования типов, производительность с использованием strings.Join будет намного выше.

func TestStr(t *testing.T) {
	a, b := "Hello", "world"
	for i := 0; i < 1000000; i++ {
		fmt.Sprintf("%s%s", a, b)
		//strings.Join([]string{a, b}, "")
	}
}

PASS: TestStr (0.29s)

func TestStr(t *testing.T) {
	a, b := "Hello", "world"
	for i := 0; i < 1000000; i++ {
		//fmt.Sprintf("%s%s", a, b)
		strings.Join([]string{a, b}, "")
	}
}

PASS: TestStr (0.09s)

Судя по результатам, strings.Join примерно в 4 раза быстрее, чем Sprint.

2. Для пар "ключ-значение" с фиксированными полями используйте временную структуру вместо интерфейса map[string]{}.

Возьмем простой пример

func TestData(t *testing.T) {

	for i := 0; i < 100000000; i++ {
		var a struct {
			Name string
			Age  int
		}
		a.Name = "Hello"
		a.Age = 10
	}
}

PASS: TestData (0.04s)

func TestData2(t *testing.T) {

	for i := 0; i < 100000000; i++ {
		var a = map[string]interface{}{}
		a["Name"] = "Hello"
		a["Age"] = 10
	}
}

PASS: TestData2 (38.30s)

Разница в тысячи раз эффективнее! В случае знания полей использование временной структуры не требует динамического выделения содержимого во время выполнения и не требует проверки индекса, как карты, поэтому это будет намного быстрее.