Go의 문자열 비교 최적화

Go 프로그램이 더 빨리 실행되기를 원합니까?문자열 비교를 최적화하면 응용 프로그램의 응답 시간을 높일 수 있고 확장성을 높일 수 있다.두 문자열이 같은지 아닌지를 비교하려면 처리 능력이 필요하지만 모든 비교가 같지는 않습니다.이전 글에서 우리는 How to compare strings in 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 testing package
  • 의 이름은 compare_test입니다.고고야, 여기서 테스트 찾는 거 알아.
  • 우리는 테스트가 아니라 기준을 삽입했다.모든 func 앞에는 기준이 있어야 합니다.
  • 우리는 테스트 데스크톱 로고
  • 를 사용하여 테스트를 실행할 것이다
    데이텀 테스트를 실행하려면 다음 명령을 사용합니다.
    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!

    좋은 웹페이지 즐겨찾기