Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby 2.5 성능 개선 총정리: 문자열 보간부터 Enumerable까지, 벤치마크로 검증한 최적화

Ruby는 새 버전이 출시될 때마다 꾸준히 성능이 향상되어 왔으며, Ruby 2.5 역시 예외가 아닙니다.

Ruby 2.5에 도입된 주요 최적화는 다음과 같습니다.

  • 큰 문자열을 생성할 때 문자열 보간(string interpolation) 속도가 약 72% 향상됩니다
  • 인자가 하나만 전달될 때 String#prepend 속도가 약 42% 향상됩니다
  • Enumerable#sort_by, Enumerable#min_by, Enumerable#max_by 속도가 약 50% 향상됩니다

그럼 실제 벤치마크 결과를 함께 살펴보겠습니다!

문자열 보간(String Interpolation) 성능

이번 최적화의 커밋 메시지에 포함된 예제 코드를 활용해 벤치마크를 진행했습니다.

require 'benchmark/ips'

Benchmark.ips do |x|
  x.report "Large string interpolation" do |t|
    a = "Hellooooooooooooooooooooooooooooooooooooooooooooooooooo"
    b = "Wooooooooooooooooooooooooooooooooooooooooooooooooooorld"

    t.times { "#{a}, #{b}!" }
  end

  x.report "Small string interpolation" do |t|
    a = "Hello"
    b = "World"

    t.times { "#{a}, #{b}!" }
  end

  x.compare!
end

실행 결과는 다음과 같습니다.

Ruby 2.4.1:

Small string interpolation:  3236291.1 i/s
Large string interpolation:  1711633.4 i/s - 1.89x  slower

Ruby 2.5:

Small string interpolation:  3125175.1 i/s
Large string interpolation:  2555782.6 i/s - 1.22x  slower

결과에서 확인할 수 있듯이, 큰 문자열을 다룰 때의 성능 차이가 상당히 두드러집니다!

String#prepend 성능

prepend 메서드는 문자열 앞에 다른 문자열을 삽입할 때 사용합니다.

Ruby 2.5는 가장 흔한 사용 사례인, 단일 문자열을 다른 문자열 앞에 추가하는 경우에 맞춰 최적화되었습니다.

벤치마크 결과는 다음과 같습니다.

Ruby 2.4.1 결과:

String#prepend  3.428M (± 3.2%) i/s - 17.159M in   5.011008s

Ruby 2.5 결과:

String#prepend  4.638M (± 3.6%) i/s - 23.276M in   5.025562s

꽤 인상적인 성능 향상입니다!

Enumerable 성능 개선

여러 Enumerable 메서드들도 성능이 크게 개선되었습니다.

이 최적화가 가능한 핵심 이유는 <=> 메서드 호출을 위한 디스패칭(method dispatching) 과정을 생략하기 때문입니다.

커밋 메시지에는 다음과 같이 설명되어 있습니다.

"Fixnum/Float/String 객체를 비교할 때 <=> 메서드 디스패칭 대신 OPTIMIZED_CMP()를 사용합니다."

실제 벤치마크 결과는 아래와 같습니다.

Ruby 2.4.2:

Enumerable#sort_by    2.395k (± 6.7%) i/s - 11.952k in   5.014422s
Enumerable#min_by     8.244k (± 6.1%) i/s - 41.405k in   5.042327s
Enumerable#max_by     8.053k (± 6.7%) i/s - 40.180k in   5.015375s

Ruby 2.5:

Enumerable#sort_by    5.914k (± 6.7%) i/s  - 29.786k in   5.062584s
Enumerable#min_by     15.668k (± 3.0%) i/s - 78.888k in   5.039748s
Enumerable#max_by     15.544k (± 2.3%) i/s - 78.408k in   5.046709s

무려 약 50%의 성능 향상입니다 🙂

Range#min & Range#max

추가로 알려드릴 성능 최적화가 두 가지 더 있습니다!

첫 번째는 Range#minRange#max 메서드 관련 개선 사항입니다.

벤치마크 결과는 다음과 같습니다.

Ruby 2.4.2

Range#min    7.976M (± 3.0%) i/s - 39.950M in   5.013242s
Range#max    7.996M (± 3.4%) i/s - 40.059M in   5.015984s

Ruby 2.5

Range#min   13.154M (± 3.0%) i/s -  65.731M in   5.002094s
Range#max  13.021M (± 2.6%) i/s  -  65.202M in   5.010924s

관련 커밋은 Ruby 저장소에서 직접 확인하실 수 있습니다.

개선된 String#scan

커밋 메시지에 따르면, String#scan은 문자열 패턴 사용 시 50%, 정규식(regex) 패턴 사용 시 10%의 성능 향상을 보입니다.

벤치마크 결과를 살펴보겠습니다.

Ruby 2.4.2

String#scan - String pattern
       1.367M (±19.8%) i/s - 6.458M in   4.982047s
String#scan - Regex pattern
       1.228M (±17.0%) i/s - 5.881M in   4.983943s

Ruby 2.5

String#scan - String pattern
      3.944M (±24.4%) i/s - 17.739M in   4.977417s
String#scan - Regex pattern
      1.696M (±17.4%) i/s -  8.103M in   4.982614s

더 빨라진 스캔 기능을 마음껏 활용해 보세요!

마무리

이번 글에서는 12월 25일 출시 예정인 Ruby 2.5에 포함될 새로운 성능 최적화들을 살펴보았습니다.

핵심 개선 사항은 문자열 보간, Enumerable 메서드, String#prepend, String#scan, 그리고 Range#max / Range#min 메서드와 관련되어 있습니다.

글이 도움이 되었기를 바랍니다!

유익했다면 좋아하는 소셜 네트워크에 공유하는 것도 잊지 마세요 🙂