Какой лучше получить последний символ Х строки Golang? - PullRequest
0 голосов
/ 01 февраля 2019

Когда у меня есть строка "hogemogehogemogehogemoge 世界 世界 世界", какой код лучше получить последней руной, избегая выделения памяти?

Есть похожий вопрос о том, чтобы получить последний символ X строки Golang.

Как получить последние X символов строки Голанга?

Я хочу убедиться, что предпочтительнее, если я просто хочу получить последнюю руну, безлюбая дополнительная операция.

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    // which is more better for memory allocation?
    s := "hogemogehogemogehogemoge世界世界世界a"
    getLastRune(s, 3)
    getLastRune2(s, 3)
}

func getLastRune(s string, c int) {
    // DecodeLastRuneInString
    j := len(s)
    for i := 0; i < c && j > 0; i++ {
        _, size := utf8.DecodeLastRuneInString(s[:j])
        j -= size
    }
    lastByRune := s[j:]
    fmt.Println(lastByRune)
}

func getLastRune2(s string, c int) {
    // string -> []rune
    r := []rune(s)
    lastByRune := string(r[len(r)-c:])
    fmt.Println(lastByRune)
}

世界 a

世界 a

1 Ответ

0 голосов
/ 01 февраля 2019

Когда речь идет о производительности и распределении ресурсов, вы должны запускать тесты.

Сначала давайте изменим ваши функции, чтобы они не печатали, а возвращали результат:

func getLastRune(s string, c int) string {
    j := len(s)
    for i := 0; i < c && j > 0; i++ {
        _, size := utf8.DecodeLastRuneInString(s[:j])
        j -= size
    }
    return s[j:]
}

func getLastRune2(s string, c int) string {
    r := []rune(s)
    if c > len(r) {
        c = len(r)
    }
    return string(r[len(r)-c:])
}

И функции бенчмарка:

var s = "hogemogehogemogehogemoge世界世界世界a"

func BenchmarkGetLastRune(b *testing.B) {
    for i := 0; i < b.N; i++ {
        getLastRune(s, 3)
    }
}

func BenchmarkGetLastRune2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        getLastRune2(s, 3)
    }
}

Запуск их:

go test -bench . -benchmem

Результаты:

BenchmarkGetLastRune-4     30000000     36.9 ns/op     0 B/op    0 allocs/op
BenchmarkGetLastRune2-4    10000000    165 ns/op       0 B/op    0 allocs/op

getLastRune() более чем в 4 раза быстрее .Ни один из них не выполняет никаких выделений, но это происходит из-за оптимизации компилятора (преобразование string в []rune и обратно обычно требует выделения).

Если мы запускаем тесты с отключенной оптимизацией:

go test -gcflags '-N -l' -bench . -benchmem

Результаты:

BenchmarkGetLastRune-4     30000000    46.2 ns/op      0 B/op    0 allocs/op
BenchmarkGetLastRune2-4    10000000   197 ns/op       16 B/op    1 allocs/op

Оптимизация компилятора или нет, getLastRune() - явный победитель.

...