Go 코드 작업을 1.5배 더 빠르게 또는 그 이상으로

소개



성능은 모든 것의 핵심이며, 우리(인간)는 기다리거나 시간을 낭비하는 것을 좋아하지 않습니다. 따라서 때로는 대부분의 관리자가 생각하는 빠른 솔루션이 느린 것보다 낫지만 우수한 엔지니어링 및 디자인을 갖추고 있습니다. 그러나 오늘 우리는 관리에 대해 말하는 것이 아니라 코드 성능에 대해 이야기하고 있습니다. 보기 방식에서 편리하게 템플릿을 사용하여 텍스트 서식을 지정할 수 있는 small text formatting library이 있습니다. 이것들 . 우리 모듈의 이전 버전은 성능이 fmt.Sprintf 로 느슨했지만 1.0.1부터는 더 좋아졌습니다. 그리고 오늘 우리는 golang 코드를 더 빠르게 작동시키는 방법을 알려줄 것입니다.

매개변수 및 반환 값



인수를 전달하거나 함수 결과를 가져오는 두 가지 옵션이 있습니다. 포인터 및 값으로 다음 예제를 고려하십시오.

func getItemAsStr(item *interface{}) string   // 1st variant
func getItemAsStr(item interface{})  string   // 2nd variant
func getItemAsStr(item *interface{}) *string  // 3rd variant
func getItemAsStr(item interface{})  *string  // 4th variant


성능 테스트에 따르면 다음과 같은 결론을 내릴 수 있습니다.
  • 인수 복사를 제거했기 때문에 포인터로 인수를 전달할 때 약간의 성능 향상이 있습니다.
  • 함수 로컬 변수에 대한 포인터를 반환하면 성능이 저하됩니다
  • .

    따라서 가장 최적의 변형은 첫 번째 변형입니다.

    문자열



    문자열은 다른 많은 프로그래밍 언어와 마찬가지로 변경할 수 없으므로 + 연산자를 사용하여 문자열을 연결하는 것은 좋지 않습니다. 즉, 다음과 같은 코드는 매우 느립니다.

    var result string = ""
    for _, arg := range args {
        result += getItemAsStr(&arg)
    }
    


    모든 "+"는 결과적으로 메모리 사용량이 증가함에 따라 새 문자열 개체를 생성하고 새 변수에 대한 할당에 충분한 시간을 소비하여 성능이 크게 저하됩니다.

    strings.Builder를 사용하는 문자열 concat에 대한 더 나은 솔루션이 있지만 더 나은 성능을 위해 초기에 버퍼를 확대하여(Grow 함수 사용) 일부/모든 재할당을 방지해야 하지만 버퍼 크기가 매우 큰 경우 초기 메모리 할당이 느려져 성능이 저하될 수 있으므로 초기 버퍼 크기를 현명하게 선택해야 합니다.

    var formattedStr = &strings.Builder{}
    formattedStr.Grow(templateLen + 22*len(args))
    


    주기



    컬렉션을 반복하는 방법에는 두 가지가 있습니다.
  • range 식 사용

  •   for _, arg := range args {
          // do some staff here
      }
    


  • 전통적인 for를 3가지 표현으로 사용:

  •   for i := start; i < templateLen; i++ {
          // do some staff here
      }
    


    두 번째 변형은 성능면에서 더 좋습니다. 그러나 3가지 표현식을 사용하면 추가적인 이점for이 있습니다.
  • 반복 횟수 감소, 반복 코드가 많을수록 느려짐,
    따라서 루프 값에 영향을 줄 수 있으면 그렇게 하십시오. 이것range 로 달성할 수 없음 ;
  • 가능한 경우 반복에 대한 초기 값을 훨씬 높게 설정합니다.
    즉, 우리의 경우:

  •   start := strings.Index(template, "{")
      if start < 0 {
         return template
      }
    
      formattedStr.WriteString(template[:start])
      for i := start; i < templateLen; i++ {
          // iterate over i
      }
    


    결론



    이러한 간단한 기술을 사용하여 코드를 이전보다 1.5배 더 빠르게 실행했으며 이제 fmt.Sprintf보다 더 빠르게 작동합니다. 성능 측정을 참조하십시오.


    . 또한 fmt.Sprintf 대신 our library 을 사용하는 것이 좋습니다. SQL 쿼리 또는 이와 유사한 항목에 대한 문자열을 준비하는 경우 가능한 한 빠르게 만드는 것이 중요하기 때문입니다. Github에서 별표를 주고 여기와 Github에서도 우리 조직을 팔로우하기 시작하면 감사하겠습니다.

    좋은 웹페이지 즐겨찾기