흔한 병목
Ruby 코드의 속도를 높입니다
흔한 병목은(는) CoddyKit의 무료 Ruby Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Ruby Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Ruby Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
병목 인식하기
Ruby에서 느려지는 현상은 대부분 반복해서 나타나는 몇 가지 패턴에서 비롯됩니다. 이를 알면 코드를 빠르게 고칠 수 있습니다.
- 작업에 맞지 않는 자료 구조
- 캐시할 수 있는데도 반복하는 작업
- N+1 질의와 중첩 루프
이 학습에서는 가장 흔한 원인을 다룹니다.
puts 'Speeding up Ruby starts with knowing the usual suspects'Array#include?와 Set 비교
Array#include?로 포함 여부를 확인하면 O(n)입니다. Set(또는 해시)을 사용하면 조회가 O(1)이 됩니다.
- 포함 여부를 반복해서 확인해야 한다면 Set을 한 번 만드세요
- 큰 컬렉션에서 속도가 크게 향상됩니다
require 'set'
allowed = Set.new(['a', 'b', 'c'])
puts allowed.include?('b')
puts allowed.include?('z')중첩 루프(O(n의 제곱))
모든 요소 쌍을 비교하면 시간 복잡도가 제곱으로 증가하며, 규모가 커질수록 폭발적으로 느려집니다.
- 내부 루프를 해시 조회로 바꿉니다
- O(n의 제곱)을 O(n)으로 바꿉니다
a = [1, 2, 3, 4]
b = [3, 4, 5]
set_b = b.to_set rescue require('set') || b.to_set
common = a.select { |x| set_b.include?(x) }
puts common.inspectN+1 패턴
루프 안에서 관련 데이터를 가져오면 N+1번 작업이 발생합니다.
- 목록에 대해 질의 1번을 실행한 다음 항목마다 1번씩 실행합니다
- 대신 한 번의 그룹 조회로 일괄 처리합니다
# Bad: lookup inside loop
orders = [1, 2, 3]
prices = { 1 => 10, 2 => 20, 3 => 30 }
# Good: one preloaded hash, O(1) per item
total = orders.sum { |id| prices[id] }
puts total메모이제이션
비용이 큰 값을 매번 다시 계산하면 시간이 낭비됩니다. ||=로 메모이제이션하세요.
- first 계산 후 결과를 캐시합니다
- 이후 호출은 즉시 결과를 반환합니다
class Report
def total
@total ||= begin
puts 'computing...'
(1..1000).sum
end
end
end
r = Report.new
puts r.total
puts r.total알맞은 메서드 선택하기
일부 Enumerable 메서드는 메서드 체인보다 훨씬 빠릅니다.
sum이inject(:+)보다 빠릅니다any?는select.empty?와 달리 조건을 만족하는 항목을 찾으면 즉시 중단합니다find는 first 일치 항목에서 멈춥니다
nums = (1..1_000_000)
puts nums.any? { |n| n > 5 }
puts nums.find { |n| n > 5 }반복 정렬 피하기
루프 안에서 정렬하거나 정렬을 반복하면 비용이 큽니다. 한 번 정렬한 결과를 재사용하세요.
- 정렬의 시간 복잡도는 O(n log n)입니다
- 데이터가 변하지 않는다면 정렬된 결과를 캐시합니다
data = [5, 2, 8, 1, 9]
sorted = data.sort
puts sorted.first
puts sorted.last해시로 그룹화하기
group_by와 tally는 반복해서 순회하는 대신 한 번의 순회로 집계합니다.
tally는 출현 횟수를 효율적으로 셉니다- 수동으로 세는 루프를 피할 수 있습니다
words = ['a', 'b', 'a', 'c', 'b', 'a']
puts words.tally.inspect문자열 생성 비용
컬렉션에서는 반복해서 연결하는 것보다 join으로 결합하는 편이 빠릅니다.
- 배열을 만든 다음
join을 한 번 호출합니다 - 중간 문자열을 여러 개 만들지 않습니다
parts = (1..5).map { |i| "item#{i}" }
puts parts.join(', ')정규식 컴파일
자주 실행되는 루프 안에 정규식 리터럴을 정의하면 암묵적으로 다시 컴파일됩니다. 상수로 바깥에 옮기세요.
- 한 번 컴파일하고 여러 번 일치시킵니다
- 부울값만 필요할 때는
match?를 사용합니다
EMAIL = /\A[^@\s]+@[^@\s]+\z/
inputs = ['a@b.com', 'nope', 'x@y.org']
valid = inputs.select { |s| EMAIL.match?(s) }
puts valid.inspect작업 지연 실행
사용하지 않을 수도 있는 것은 계산하지 마세요. 지연 평가나 가드 조건으로 처리를 미루세요.
- 가능하면 일찍 반환합니다
- 요청이 있을 때만 무거운 값을 계산합니다
def describe(items)
return 'empty' if items.empty?
"#{items.size} items, first is #{items.first}"
end
puts describe([])
puts describe([10, 20])빠른 확인
병목에 대한 지식을 확인해 보세요.
복습
흔한 병목을 해결하는 방법을 배웠습니다:
include?대신 빠른 포함 여부 확인을 위해 Set이나 해시를 사용합니다- 미리 불러온 해시로 중첩 루프와 N+1 패턴을 없앱니다
||=로 비용이 큰 계산을 메모이제이션합니다- 효율적인 메서드(
sum,any?,tally)를 선택하고 정규식을 바깥으로 옮깁니다 - 필요하지 않을 수도 있는 작업은 미루거나 건너뜁니다
효과를 확인하려면 항상 전후를 측정하세요.
자주 묻는 질문
“흔한 병목” 강의는 무료인가요?
네 — “흔한 병목” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Ruby Academy 강의 전체를 잠금 해제할 수 있습니다. Ruby Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“흔한 병목”에서 뭘 배우나요?
Ruby 코드의 속도를 높입니다 브라우저에서 직접 실행하는 실습 코드로 Ruby Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Ruby Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Ruby Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“흔한 병목” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Ruby Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Ruby Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.