# 루비 3.3 출시

> Clean Markdown view of GeekNews topic #12531. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=12531](https://news.hada.io/topic?id=12531)
- GeekNews Markdown: [https://news.hada.io/topic/12531.md](https://news.hada.io/topic/12531.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2023-12-26T10:00:35+09:00
- Updated: 2023-12-26T10:00:35+09:00
- Original source: [ruby-lang.org](https://www.ruby-lang.org/en/news/2023/12/25/ruby-3-3-0-released/)
- Points: 1
- Comments: 1

## Topic Body

### Ruby 3.3.0 출시

- Ruby 3.3.0 버전이 출시됨. 새로운 파서인 Prism 도입, 파서 생성기로 Lrama 사용, 순수 Ruby로 작성된 JIT 컴파일러 RJIT 추가, 특히 YJIT의 성능 개선이 이루어짐.

#### Prism 파서

- Prism은 Ruby 언어를 위한 이식 가능하고, 오류에 강하며, 유지보수가 용이한 재귀 하향 파서로 기본 gem으로 제공됨.
- Prism은 생산 환경에 적합하며 활발히 유지보수되고 있으며, Ripper를 대체하여 사용 가능함.
- Prism 사용법에 대한 상세한 문서 제공됨.
- Prism은 CRuby 내부에서 사용되는 C 라이브러리이자 Ruby 코드를 파싱할 필요가 있는 모든 도구에서 사용할 수 있는 Ruby gem임.
- Prism API의 주요 메소드로는 `Prism.parse(source)`, `Prism.parse_comments(source)`, `Prism.parse_success?(source)` 등이 있음.
- Prism 저장소에 직접 pull request나 이슈를 제출하여 기여할 수 있음.
- Prism 컴파일러를 실험적으로 사용하려면 `ruby --parser=prism` 또는 `RUBYOPT="--parser=prism"`를 사용할 수 있으나, 디버깅 목적으로만 사용해야 함.

#### Lrama 파서 생성기

- Bison을 Lrama LALR 파서 생성기로 대체함.
- Ruby의 파서에 대한 미래 비전을 참조하면 관심 있는 사람들이 확인할 수 있음.
- 유지보수를 위해 내부 Lrama 파서가 Racc에 의해 생성된 LR 파서로 교체됨.
- 파라미터화 규칙 (?, *, +) 지원, Ruby parse.y에서 사용될 예정임.

#### YJIT

- Ruby 3.2 대비 주요 성능 개선 사항이 있음.
- splat 및 rest 인자에 대한 지원이 개선됨.
- 가상 머신의 스택 작업에 대해 레지스터가 할당됨.
- 선택적 인자가 있는 더 많은 호출이 컴파일됨. 예외 처리기도 컴파일됨.
- 지원되지 않는 호출 유형 및 메가모픽 호출 사이트는 더 이상 인터프리터로 나가지 않음.
- Rails의 `#blank?` 및 특수한 `#present?`와 같은 기본 메소드가 인라인 처리됨.
- `Integer#*`, `Integer#!=`, `String#!=`, `String#getbyte`, `Kernel#block_given?`, `Kernel#is_a?`, `Kernel#instance_of?`, `Module#===` 등이 특별히 최적화됨.
- 컴파일 속도가 Ruby 3.2보다 약간 빨라짐.
- Optcarrot에서 인터프리터보다 3배 이상 빠름!
- Ruby 3.2 대비 메모리 사용량이 크게 개선됨.
- 컴파일된 코드의 메타데이터가 훨씬 적은 메모리를 사용함.
- `--yjit-call-threshold`가 30에서 40,000개 이상의 ISEQ가 있는 애플리케이션의 경우 120으로 자동으로 상승됨.
- `--yjit-cold-threshold`가 추가되어 냉각된 ISEQ의 컴파일을 건너뜀.
- Arm64에서 더 컴팩트한 코드가 생성됨.
- 코드 GC는 기본적으로 비활성화됨.
- `--yjit-exec-mem-size`는 새 코드 컴파일이 중단되는 하드 리밋으로 처리됨.
- 코드 GC로 인한 성능 저하가 없으며, Pitchfork를 사용하여 서버가 리포킹할 때 더 나은 복사-쓰기 동작을 보임.
- 원하는 경우 `--yjit-code-gc`로 코드 GC를 활성화할 수 있음.
- `RubyVM::YJIT.enable`을 추가하여 실행 시간에 YJIT를 활성화할 수 있음.
- Rails 7.2는 이 방법을 사용하여 기본적으로 YJIT를 활성화할 예정임.
- 애플리케이션이 부팅을 완료한 후에만 YJIT를 활성화하려면 이 방법을 사용할 수 있음.
- 부팅 시 YJIT를 비활성화하면서 다른 YJIT 옵션을 사용하려면 `--yjit-disable`을 사용할 수 있음.
- 기본적으로 더 많은 YJIT 통계가 제공됨.
- `yjit_alloc_size` 및 여러 메타데이터 관련 통계가 기본적으로 제공됨.
- `--yjit-stats`에 의해 생성된 `ratio_in_yjit` 통계가 릴리스 빌드에서 사용 가능함. 특별한 통계 또는 개발 빌드가 더 이상 필요하지 않음.
- 더 많은 프로파일링 기능이 추가됨.
- `--yjit-perf`가 Linux perf와 함께 프로파일링을 용이하게 하기 위해 추가됨.
- `--yjit-trace-exits`가 `--yjit-trace-exits-sample-rate=N`을 사용한 샘플링을 지원함.
- 더 철저한 테스트와 다수의 버그 수정이 이루어짐.

#### RJIT

- 순수 Ruby로 작성된 JIT 컴파일러 RJIT이 도입되고 MJIT이 대체됨.
- RJIT은 Unix 플랫폼의 x86-64 아키텍처에서만 지원됨.
- MJIT과 달리, 런타임에 C 컴파일러가 필요하지 않음.
- RJIT은 실험적인 목적으로만 존재함.
- 생산 환경에서는 YJIT을 계속 사용해야 함.
- Ruby JIT 개발에 관심이 있는 경우, RubyKaigi의 3일차에 있는 k0kubun의 발표를 확인할 것을 권장함.

#### M:N 스레드 스케줄러

- M:N 스레드 스케줄러가 도입됨.
- M Ruby 스레드가 N 네이티브 스레드(운영 체제 스레드)에 의해 관리되므로 스레드 생성 및 관리 비용이 감소함.
- M:N 스레드 스케줄러는 C 확장과 호환성을 깰 수 있으므로 기본적으로 메인 Ractor에서 비활성화됨.
- `RUBY_MN_THREADS=1` 환경 변수를 사용하여 메인 Ractor에서 M:N 스레드를 활성화할 수 있음.
- 비메인 Ractor에서는 항상 M:N 스레드가 활성화됨.
- `RUBY_MAX_CPU=n` 환경 변수는 N의 최대 개수(네이티브 스레드의 최대 개수)를 설정함. 기본값은 8임.
- Ractor당 하나의 Ruby 스레드만 실행될 수 있으므로, 싱글 Ractor 애플리케이션(대부분의 애플리케이션)은 1개의 네이티브 스레드만 사용함.
- 차단 작업을 지원하기 위해 N보다 많은 네이티브 스레드가 사용될 수 있음.

#### 성능 개선

- `defined?(@ivar)`가 Object Shapes를 사용하여 최적화됨.
- `Socket.getaddrinfo`와 같은 이름 해석이 이제 인터럽트될 수 있음(사용 가능한 환경에서 pthreads가 있는 경우).
- 가비지 컬렉터에 대한 여러 성능 개선 사항이 있음.
  - 젊은 객체가 노인 객체에 의해 참조되면 즉시 노인 세대로 승격되지 않아 주요 GC 수집 빈도가 크게 감소함.
  - 주요 GC 수집을 유발하는 보호되지 않은 객체의 수를 제어하는 새로운 `REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO` 조정 변수가 도입됨. 기본값은 0.01(1%)로 설정되어 주요 GC 수집 빈도가 크게 감소함.
  - Write Barriers가 누락된 많은 핵심 유형에 대해 구현됨. 이로 인해 소규모 GC 수집 시간과 주요 GC 수집 빈도가 크게 감소함.
  - 대부분의 핵심 클래스가 이제 Variable Width Allocation을 사용함. 이로 인해 이러한 클래스의 할당 및 해제가 더 빨라지고 메모리 사용량이 줄어들며 힙 단편화가 감소함.
  - 가비지 컬렉터에 약한 참조 지원이 추가됨.

#### 기타 주목할 만한 변경 사항

- IRB는 고급 irb:rdbg 통합, ls, show_source 및 show_cmds 명령에 대한 페이저 지원, ls 및 show_source 명령에 의해 제공되는 정보의 정확성 및 유용성 향상, 타입 분석을 사용한 실험적 자동 완성 등을 포함하여 여러 개선 사항을 받음.
- IRB는 또한 향후 개선을 용이하게 하기 위해 광범위한 리팩토링을 거치고 수십 개의 버그 수정을 받음.

#### 호환성 문제

- 인자 없이 블록 내에서 `it` 호출은 더 이상 사용되지 않으며, Ruby 3.4에서는 첫 번째 블록 매개변수를 참조하게 됨.
- 사용되지 않는 환경 변수가 제거됨.

#### 표준 라이브러리 업데이트

- RubyGems과 Bundler는 사용자가 Gemfile이나 gemspec에 추가하지 않고 다음 gem을 요구할 경우 경고를 표시함. 이는 해당 gem들이 미래 버전의 Ruby에서 번들 gem이 될 예정이기 때문임.
- 다음과 같은 기본 gem이 추가되거나 업데이트됨: prism 0.19.0, RubyGems 3.5.3, abbrev 0.1.2 등 다수.
- 다음과 같은 번들 gem이 기본 gem에서 승격되거나 업데이트됨: racc 1.7.3, minitest 5.20.0 등 다수.

#### GN⁺의 의견

- **Prism 파서 도입**: Ruby 3.3.0의 가장 중요한 특징 중 하나는 새로운 Prism 파서의 도입이다. 이는 Ruby 코드를 더 효율적으로 파싱하고, 오류에 강하며, 유지보수가 쉬운 파서를 제공함으로써 Ruby 개발자들에게 큰 도움이 될 것이다.
- **YJIT의 성능 개선**: YJIT의 주요 성능 개선은 Ruby 애플리케이션의 실행 속도를 크게 향상시킬 것이며, 특히 메모리 사용량 감소와 GC 최적화는 대규모 Ruby 애플리케이션의 성능과 안정성에 긍정적인 영향을 미칠 것이다.
- **M:N 스레드 스케줄러**: M:N 스레드 스케줄러의 도입은 멀티스레딩 Ruby 애플리케이션의 성능을 개선할 수 있는 잠재력을 가지고 있다. 이는 스레드 관리 비용을 줄이고, 더 효율적인 병렬 처리를 가능하게 할 것이다.

## Comments



### Comment 21718

- Author: neo
- Created: 2023-12-26T10:00:35+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=38760477) 
- Ruby 3.3의 등장으로, 개발자의 행복을 중시하는 언어인 Ruby가 이전의 느린 이미지를 벗어나 빠른 속도를 자랑함.
  - YJIT 기술과 객체 형태, GC 최적화 등의 혁신을 통해 Ruby의 성능이 크게 향상됨.
  - Shopify와 같은 대형 Ruby 사용 업체들이 Ruby 3.3의 성능 개선을 경험하고 있음.
  - Ruby의 미래에 대해 개인적으로 매우 기대하고 있으며, Ruby 3.3을 고객의 프로덕션 사이트에 적용하는 데 기대감을 표함.

- Ruby 3.3은 지난 10년간 가장 중요하고 기능이 풍부한 릴리스로, Python보다 먼저 JIT를 출시한 것에 대해 놀라움을 표함.
  - Prism, Lrama, IRB 등 다양한 기능들이 이전 해커뉴스 제출에서 논의됨.
  - Ractor, M:N 스레드 스케줄러, Fibre, Async와 같은 기능들이 Rails의 맥락에서 충분히 언급되지 않았으며, 이 기능들을 프로덕션에서 사용하는 사람들의 경험을 듣고 싶어함.

- Heroku에서 Ruby 3.3을 사용할 수 있음을 알림.

- 매년 크리스마스마다 Ruby 언어는 새로운 릴리스를 출시함.

- Python과 NodeJS를 이미 알고 있는 경우, Ruby를 배우는 것이 가치가 있는지에 대한 질문을 함. Ruby를 매력적이지만 어렵게 느낌.

- `Socket.getaddrinfo`와 같은 이름 해석이 중단될 수 있음. 이름 해석이 필요할 때마다 워커 pthread를 생성하고 `getaddrinfo(3)`를 실행함.
  - 다른 언어 런타임도 비슷한 작업을 하는지에 대한 질문을 함. 스레드 생성이 무겁게 느껴질 수 있지만, 벤치마크에 따르면 오버헤드는 최소화되어 있음.

- Prism이 흥미로움. Ruby 코드 분석 도구로 Prism을 사용하는 예가 있는지에 대한 질문을 함.

- `RUBY_MAX_CPU=n` 환경 변수가 네이티브 스레드의 최대 수를 설정함. 기본값은 8임.
  - 기본값이 논리 코어의 수와 같아야 하는지에 대한 의문을 제기함. Rust의 Tokio와 많은 다른 M:N 런타임들처럼.

- Prism을 사용한 좋은 예제에 대한 링크를 찾고 있음. 릴리스 페이지에서 "주목할 만한 API" 외에는 별다른 것을 보지 못해 실망함을 표함.

- 완벽한 크리스마스 선물이라고 언급함.
