Используя символ == в golang и используя цикл для сравнения, если строка a равна строке b, какая производительность лучше? - PullRequest
0 голосов
/ 11 июня 2018
for i:=0;i<len(a);i++{
    if a[i] != b[i]{
        return false
    }
}

и просто

a == b

Я обнаружил, что одна и та же строка имеет другой адрес

a := "abc"
b := "abc"
println(&a)
println(&b)

ответ:
0xc420045f68
0xc420045f58

так == не использовать адрес для сравнения.
На самом деле, я хотел бы знать, как == сравнивает две строки.
Я долго искал в сети.Но не удалось ...

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Используйте оператор Go == для равенства string.Компиляторы Go gc и gccgo оптимизируют компиляторы.Go runtime был оптимизирован.


Этот комментарий в документации пакета strings для функции strings.Compare также имеет отношение к равенству:

Сравнение включено только для симметрии с байтами пакета.Обычно проще и всегда быстрее использовать встроенные операторы сравнения строк ==, <,> и т. Д.


В Go runtime представление string - это struct:

type StringHeader struct {
        Data uintptr    // byte array pointer
        Len  int        // byte array length
}

Когда вы присваиваете значение Go string переменной,

s := "ABC"

ячейка памяти, выделенная для переменной s, равнаустановите значение StringHeader struct, описывающее string.Адрес переменной &s указывает на struct, а не на базовый байтовый массив.

Сравнение для равенства Go string сравнивает байты базовых массивов, значения *StringHeader.Data[0:StringHeader.Len].


В Go мы используем пакет Go testing для оценки производительности.Например, сравнивая оператор Go == с двумя функциями равенства Go string:

Вывод:

$ go test equal_test.go -bench=. -benchmem
BenchmarkEqualOper-4     500000000    3.19 ns/op    0 B/op    0 allocs/op
BenchmarkEqualFunc1-4    500000000    3.32 ns/op    0 B/op    0 allocs/op
BenchmarkEqualFunc2-4    500000000    3.61 ns/op    0 B/op    0 allocs/op
$ go version
go version devel +bb222cde10 Mon Jun 11 14:47:06 2018 +0000 linux/amd64
$

equal_test.go:

package main

import (
    "reflect"
    "testing"
    "unsafe"
)

func EqualOper(a, b string) bool {
    return a == b
}

func EqualFunc1(a, b string) bool {
    if len(a) != len(b) {
        return false
    }
    for i := 0; i < len(a); i++ {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

func EqualFunc2(a, b string) bool {
    if len(a) != len(b) {
        return false
    }
    if len(a) == 0 {
        return true
    }
    // string intern equality
    if (*reflect.StringHeader)(unsafe.Pointer(&a)).Data == (*reflect.StringHeader)(unsafe.Pointer(&b)).Data {
        return true
    }
    for i := 0; i < len(a); i++ {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

var y, z = "aby", "abz"

func BenchmarkEqualOper(B *testing.B) {
    a, b := y, z
    for i := 0; i < B.N; i++ {
        _ = EqualOper(a, b)
    }
}

func BenchmarkEqualFunc1(B *testing.B) {
    a, b := y, z
    for i := 0; i < B.N; i++ {
        _ = EqualFunc1(a, b)
    }
}

func BenchmarkEqualFunc2(B *testing.B) {
    a, b := y, z
    for i := 0; i < B.N; i++ {
        _ = EqualFunc2(a, b)
    }
}
0 голосов
/ 11 июня 2018

Вы должны использовать оператор == для сравнения строк.Он сравнивает содержимое значений string.

Что вы печатаете, это адрес переменных a и b.Поскольку они представляют собой две разные переменные ненулевого размера, их адреса не могут быть одинаковыми по определению.Ценности, которые они имеют, конечно, могут совпадать или не совпадать.Оператор == сравнивает значения, которые содержат переменные, а не адреса переменных.

Ваше решение с циклом может даже привести к панике во время выполнения, если строка b короче a, так как вы индексируете его значениями, которые действительны для a.

Встроенный оператор ==, вероятно, всегда будет превосходить любой цикл, как это реализовано в коде сборки для конкретной архитектуры.Он реализован в пакете runtime, неэкспортированная функция memequal().

Также обратите внимание, что встроенное сравнение может даже не проверять фактическое содержимое текстов, если их заголовок строки указывает на те же данные (и имеют одинаковую длину).Нет причин не использовать ==.

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

...