Go의 문자열 비교 최적화
이것은 보기에는 사소한 일일 수도 있지만, 모든 우수한 최적화기가 알고 있는 바와 같이, 축적된 것이 많다.시작합시다.
대소문자 구분 비교 측정
우선 두 종류의 문자열 비교를 측정해 봅시다.
메서드 1: 비교 연산자 사용
if a == b {
return true
}else {
return false
}
메서드 2: 문자열을 사용합니다.비교하다
if strings.Compare(a, b) == 0 {
return true
}
return false
그래서 우리는 첫 번째 방법이 더 간단하다는 것을 안다.우리는 표준 라이브러리에서 어떤 패키지도 도입할 필요가 없고, 코드도 조금 적다.공평한데, 어느 것이 더 빠릅니까?어디 보자.처음에, 우리는 테스트 파일로 응용 프로그램을 설정할 것이다.Go 테스트 도구의 데이텀 테스트 유틸리티를 사용합니다.
비교하다가다
package main
import (
"strings"
)
func main() {
}
// operator compare
func compareOperators(a string, b string) bool {
if a == b {
return true
}else {
return false
}
}
// strings compare
func compareString(a string, b string) bool {
if strings.Compare(a, b) == 0 {
return true
}
return false
}
테스트를 생성합니다.비교 테스트.가다
package main
import (
"testing"
)
func BenchmarkCompareOperators(b *testing.B) {
for n := 0; n < b.N; n++ {
compareOperators("This is a string", "This is a strinG")
}
}
func BenchmarkCompareString(b *testing.B) {
for n := 0; n < b.N; n++ {
compareString("This is a string", "This is a strinG")
}
}
문자열의 예시에 있어서, 나는 모든 문자열을 해석할 수 있도록 마지막 문자를 변경할 것이다.만약 당신이 이렇게 한 적이 없다면, 주의하십시오.
데이텀 테스트를 실행하려면 다음 명령을 사용합니다.
go test -bench=.
다음은 내 결과입니다.따라서 Strings 패키지를 사용하는 것보다 표준 비교 연산자를 사용하는 것이 더 빠릅니다.7.39나초 대 2.92나초.
여러 번 테스트를 실행하면 다음과 같은 결과가 나타납니다.
그래서 그것은 분명히 더 빠르다.5ms는 충분한 범위 내에서 큰 차이를 일으킬 수 있다.
Verdict: Basic string comparison is faster than strings package comparison for case sensitive string compares.
대소문자 구분 없는 비교 측정
우리 그것을 좀 고치자.통상적으로, 내가 문자열을 비교할 때, 나는 문자열의 테스트가 일치하는지, 어떤 문자가 대문자든 일치하는지 보고 싶다.이것은 우리의 조작에 약간의 복잡성을 증가시켰다.
sampleString := "This is a sample string"
compareString := "this is a sample string"
표준 비교를 통해 이 두 문자열은 T 대문자 때문에 같지 않다.그러나 우리는 지금 텍스트를 찾고 있다. 텍스트가 어떻게 대문자되든 상관없다.따라서 함수를 변경하여 이를 반영합니다.
// operator compare
func compareOperators(a string, b string) bool {
if strings.ToLower(a) == strings.ToLower(b) {
return true
}
return false
}
// strings compare
func compareString(a string, b string) bool {
if strings.Compare(strings.ToLower(a), strings.ToLower(b)) == 0 {
return true
}
return false
}
현재, 매번 비교하기 전에, 우리는 두 문자열을 모두 소문자로 설정합니다.이 점을 확보하기 위해서 우리는 약간의 추가 주기를 늘렸다.그것들에 대해 기준 테스트를 진행합시다.그들은 마치 같은 것 같다.다음 사항을 확인하기 위해 몇 번 실행했습니다.
그래, 그들은 똑같아.그런데 왜죠?
한 가지 이유는 우리가 매번 실행에 Strings.ToLower 조작을 추가했기 때문이다.이것은 성능이 인기 있는 것이다.문자열은 간단한 문자열입니다. ToLower () 방법은 문자열을 반복해서 소문자로 만들고 비교를 실행합니다.이 추가 시간은 동작 간의 어떠한 중대한 차이도 없앴다.
EqualFold 소개
이전 글에서 우리는 EqualFold를 대소문자를 구분하지 않고 비교하는 또 다른 방법으로 보았다.우리는 Equalfold가 세 가지 방법 중 가장 빠르다고 확신한다.이 그룹의 기준이 이 점을 반영했는지 봅시다.
비교할 항목을 추가합니다.가다
// EqualFold compare
func compareEF(a string, b string) bool {
if strings.EqualFold(sampleString, compareString) {
return true
}else {
return false
}
}
다음 테스트를 추가하여 비교_테스트를 수행합니다.가다func BenchmarkEqualFold(b *testing.B) {
for n := 0; n < b.N; n++ {
compareEF("This is a string", "This is a strinG")
}
}
이제 이 세 가지 방법으로 기준 테스트를 실행합시다.와!EqualFold 속도가 훨씬 빠릅니다.나는 같은 결과로 몇 차례 운행했다.
왜 속도가 더 빨라요?Eequalfold도 한 글자씩 문자를 해석하지만, 다른 문자를 발견하면'미리 종료'하기 때문이다.
Verdict: EqualFold (Strings Package) comparison is faster for case sensitive string compares.
저희가 테스트를 해볼게요.
좋아, 우리는 이 기준들이 방법 간의 현저한 차이를 나타낸다는 것을 안다.복잡성을 좀 더 늘려 주시겠어요?
이전 글에서 우리는 200,000 line word list를 추가하여 비교했다.일치하는 항목을 찾을 때까지 이 파일을 열고 문자열 비교를 실행하는 방법을 변경할 것입니다.
이 파일에서, 나는 파일 끝에 우리가 검색하고 있는 이름을 추가했기 때문에, 테스트가 일치하기 전에 199000개의 단어를 순환할 것을 알고 있다.
방법을 다음과 같이 변경합니다.
비교하다가다
// operator compare
func compareOperators(a string) bool {
file, err := os.Open("names.txt")
result := false;
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
if strings.ToLower(a) == strings.ToLower(scanner.Text()) {
result = true
}else {
result = false
}
}
file.Close()
return result
}
// strings compare
func compareString(a string) bool {
file, err := os.Open("names.txt")
result := false;
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
if strings.Compare(strings.ToLower(a), strings.ToLower(scanner.Text())) == 0 {
result = true
}else {
result = false
}
}
file.Close()
return result
}
// EqualFold compare
func compareEF(a string) bool {
file, err := os.Open("names.txt")
result := false;
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
if strings.EqualFold(a, scanner.Text()) {
result = true
}else {
result = false
}
}
file.Close()
return result
}
예, 이제 모두:비교 테스트.가다
func BenchmarkCompareOperators(b *testing.B) {
for n := 0; n < b.N; n++ {
compareOperators("Immanuel1234")
}
}
func BenchmarkCompareString(b *testing.B) {
for n := 0; n < b.N; n++ {
compareString("Immanuel1234")
}
}
func BenchmarkEqualFold(b *testing.B) {
for n := 0; n < b.N; n++ {
compareEF("Immanuel1234")
}
}
그래서 현재 우리는 테스트에 더 많은 시간이 걸릴 것으로 예상할 수 있기 때문에 기준 테스트 도구의 교체 횟수가 더욱 적다.다음을 실행합니다.Equal Fold는 여전히 상당한 우세로 1위를 차지했다.
이 테스트의 복잡성을 높이는 것은 좋은지 나쁜지.
좋아: 본문을 읽고 순서 테스트를 하는 것은'진실생활'시뮬레이션 같다
좋아: 우리는 서로 다른 문자열로 더욱 다양한 테스트를 강제할 수 있다
나쁜: 우리는 결과를 왜곡할 수 있는 몇 가지 요소 (파일 읽기 등) 를 도입했다.
Verdict: EqualFold (Strings Package) comparison is STILL faster for case sensitive string compares.
하지만 잠깐만, 더 있어!!
이것을 비교적 빨리 할 수 있는 방법이 있습니까?물론나는 문자열의 문자를 세어 보기로 결정했다.문자 수가 다르면 같은 문자열이 아니므로 비교에서 미리 종료할 수 있습니다.
그러나 문자열의 길이가 같지만 문자가 다르다면, 우리는 여전히 같은 길이를 포함해야 한다.추가된 계수 검사는 조작을 더욱 비싸게 합니다. 그러면 더 빠를 수 있습니까?어디 보자.
비교하다가다
func compareByCount(a string) bool {
file, err := os.Open("names.txt")
result := false;
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
if len(a) == len(scanner.Text()) && strings.EqualFold(a, scanner.Text()){
result = true
}else {
result = false
}
}
file.Close()
return result
}
비교 테스트.가다
func BenchmarkCompareByCount(b *testing.B){
for n := 0; n < b.N; n++ {
compareByCount("Immanuel1234")
}
}
그리고 얘가 더 빨라!하나하나가 중요해요.
Verdict: Do a character count with your EqualFold comparison for even more speed
총결산
본고에서 우리는 몇 가지 서로 다른 문자열 비교 방법과 어떤 방법이 더 빠른지 연구했다.한마디: 대소문자 구분에 대한 비교는 기본 비교를 사용하고, 대소문자 구분에 대한 비교는 문자 계수 + 와 같은 배를 사용한다.
나는 이런 테스트를 하는 것을 좋아한다. 네가 최적화를 할 때, 너는 작은 변화를 합치면 매우 좋다는 것을 발견할 수 있다.이러한 최적화에 관한 더 많은 글에 계속 관심을 가져 주십시오.
당신은 어떻게 생각합니까?Let me know!
Reference
이 문제에 관하여(Go의 문자열 비교 최적화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/pluralsight/optimizing-string-comparisons-in-go-4e0c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)