Эффективное соединение строк языка Go (1)

задняя часть база данных Go Язык программирования

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

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

один пример

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

昵称:飞雪无情
博客:http://www.flysnow.org/
微信公众号:flysnow_org

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

+ вышивка знака

Этот вид сплайсинга для нас самый простой и легкий в использовании, потому что он не ограничивается языками программирования, например, в языке Go он есть, в Java есть.+знаковый оператор, вычисляемый во время выполнения. Теперь продемонстрируйте код для этого сплайсинга, хотя он относительно прост.

func StringPlus() string{
	var s string
	s+="昵称"+":"+"飞雪无情"+"\n"
	s+="博客"+":"+"http://www.flysnow.org/"+"\n"
	s+="微信公众号"+":"+"flysnow_org"
	return s
}

Мы можем сами написать тест варианта использования, который может печатать тот же контент, что и в нашем примере. Итак, какова производительность этого наиболее распространенного метода сращивания строк? Давайте проверим его:

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

бегатьgo test -bench=. -benchmemПросмотрите выходные данные производительности следующим образом:

BenchmarkStringPlus-8   20000000    108 ns/op   144 B/op    2 allocs/op

Каждая операция занимает 108 нс, выполняется 2 выделения памяти и выделяется 114 байт памяти.

сшивка

Это сращивание с помощьюfmt.SprintРяд функций объединяется, а затем возвращает объединенную строку.

func StringFmt() string{
	return fmt.Sprint("昵称",":","飞雪无情","\n","博客",":","http://www.flysnow.org/","\n","微信公众号",":","flysnow_org")
}

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

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

Запустите, чтобы увидеть результаты теста:

BenchmarkStringFmt-8    5000000     385 ns/op   80 B/op     1 allocs/op

Хотя на операцию приходится только одно выделение памяти, а 80 байт — это немного, каждая операция занимает слишком много времени, а производительность далека от хорошей.+Работа с номером быстрая.

Присоединяйтесь к сплайсингу

Это используетstrings.JoinФункция выполняет конкатенацию, принимает массив строк и преобразует его в конкатенированную строку.

func StringJoin() string{
	s:=[]string{"昵称",":","飞雪无情","\n","博客",":","http://www.flysnow.org/","\n","微信公众号",":","flysnow_org"}
	return strings.Join(s,"")
}

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

Для удобства код теста производительности собран воедино, а теперь давайте посмотрим на результат теста производительности.

BenchmarkStringJoin-8   10000000    177 ns/op   160 B/op    2 allocs/op

общий и+Эксплуатация не сильно отличается, примерно в 0,5 раза ниже.

woohoo.fly snow.org/2018/10/28/…

Эффективное соединение строк языка Go (1) | Безжалостный блог Feixue

буферная строчка

Это также используется много, используяbytes.BufferСращивание струн, это очень гибкая структура, можно не только сращивать струны, но иbyte,runeи так далее, и понялio.WriterИнтерфейс также очень удобен для написания.

func StringBuffer() string {
	var b bytes.Buffer
	b.WriteString("昵称")
	b.WriteString(":")
	b.WriteString("飞雪无情")
	b.WriteString("\n")
	b.WriteString("博客")
	b.WriteString(":")
	b.WriteString("http://www.flysnow.org/")
	b.WriteString("\n")
	b.WriteString("微信公众号")
	b.WriteString(":")
	b.WriteString("flysnow_org")
	return b.String()
}

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

Посмотрите на его производительность и запустите вывод:

BenchmarkStringBuffer-8     5000000     291 ns/op   336 B/op    3 allocs/op

Вроде не очень, примерно так же, как и самая плохая прошивка fmt, и+Нет, стыковка соединений далека от хорошей, да и выделений памяти больше. Каждая операция также занимает много времени.

Строительная строчка

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

func StringBuilder() string {
	var b strings.Builder
	b.WriteString("昵称")
	b.WriteString(":")
	b.WriteString("飞雪无情")
	b.WriteString("\n")
	b.WriteString("博客")
	b.WriteString(":")
	b.WriteString("http://www.flysnow.org/")
	b.WriteString("\n")
	b.WriteString("微信公众号")
	b.WriteString(":")
	b.WriteString("flysnow_org")
	return b.String()
}

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

Официальные лица говорят, что производительность буфера лучше, чем у буфера.Посмотрим на результаты теста производительности.

BenchmarkStringBuilder-8    10000000    170 ns/op   232 B/op    4 allocs/op

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

Сравнение производительности

Вышеупомянутый является широко используемым методом сращивания струн. Теперь давайте объединим эти результаты тестов и сравним их. Поскольку эталонный тест показывает только производительность, я установил время теста на 3 с (секунды) и установил время Удлинение удобно для сравнительного анализа. тестирование, и создается файл профиля процессора для анализа производительности.

бегатьgo test -bench=. -benchmem -benchtime=3s -cpuprofile=profile.outПолучены следующие результаты испытаний:

StringPlus-8    50000000    112 ns/op   144 B/op    2 allocs/op
StringFmt-8     20000000    344 ns/op   80 B/op     1 allocs/op
StringJoin-8    30000000    171 ns/op   160 B/op    2 allocs/op
StringBuffer-8  20000000    302 ns/op   336 B/op    3 allocs/op
StringBuilder-8 30000000    171 ns/op   232 B/op    4 allocs/op

мы проходимgo tool pprof profile.outВзгляните на информацию о профиле процессора, которую мы выводим. Здесь в основном используется команда top.

Showing top 15 nodes out of 89
      flat  flat%   sum%        cum   cum%
    11.99s 42.55% 42.55%     11.99s 42.55%  runtime.kevent
     6.30s 22.36% 64.90%      6.30s 22.36%  runtime.pthread_cond_wait
     1.65s  5.86% 70.76%      1.65s  5.86%  runtime.pthread_cond_signal
     1.11s  3.94% 74.70%      1.11s  3.94%  runtime.usleep
     1.10s  3.90% 78.60%      1.10s  3.90%  runtime.pthread_cond_timedwait_relative_np
     0.58s  2.06% 80.66%      0.62s  2.20%  runtime.wbBufFlush1
     0.51s  1.81% 82.47%      0.51s  1.81%  runtime.memmove
     0.44s  1.56% 84.03%      1.81s  6.42%  fmt.(*pp).printArg
     0.39s  1.38% 85.42%      2.36s  8.37%  fmt.(*pp).doPrint
     0.36s  1.28% 86.69%      0.70s  2.48%  fmt.(*buffer).WriteString (inline)
     0.34s  1.21% 87.90%      0.93s  3.30%  runtime.mallocgc
     0.20s  0.71% 88.61%      1.20s  4.26%  fmt.(*fmt).fmtS
     0.18s  0.64% 89.25%      0.18s  0.64%  fmt.(*fmt).truncate
     0.16s  0.57% 89.82%      0.16s  0.57%  runtime.memclrNoHeapPointers
     0.15s  0.53% 90.35%      1.35s  4.79%  fmt.(*pp).fmtString

Для первых 15 видно, что метод сплайсинга fmt является наихудшим, потому что многие методы в fmt ранжируются вверху.bufferизWriteStringМетод также требует времени.

Приведенный выше ТОП может быть не слишком интуитивным, если посмотреть на флейм-график, то будет понятнее. Лучшее исполнение это+Сращивание номеров, сращивание соединений и самый медленный сплайсинг fmt.Сварка компоновщика и буферного сплайсинга здесь аналогичны, и они не проявляют свои возможности.

Суммировать

Судя по тесту и анализу всей производительности, ожидаемый нами билдер не сработал, значит ли это, что билдер не практичен? лучше+Сращивание номеров и соединений? Мы продолжим анализ в следующей статье, и вот некоторые сведения заранее: Например:

  1. размер объединенной строки
  2. Количество объединенных строк

Приведенные выше два очень важны, вы можете видеть, к какому из приведенных выше примеров относится.

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

Эта статья является оригинальной статьей, перепечатайте ее и укажите источник: «Всегда есть плохие люди, которые удаляют мое первоначальное описание, когда берут статью».flysnow_orgили сайтwww.flysnow.org/, и впервые прочитал последующие замечательные статьи. «Замечания против гнилых людей **...&*¥» Если вы считаете, что это хорошо, поделитесь им в кругу друзей, спасибо за вашу поддержку.

扫码关注