
AI에게 "속도 높여줘"라고 부탁한 코드, 10개 중 5개는 느려졌다
요약
AI에게 코드 최적화를 요청했을 때, 10개 중 5개는 오히려 실행 속도가 느려졌다는 실험 결과입니다. 코드가 깔끔해지는 리팩토링과 실제 실행 성능 향상은 별개임을 보여줍니다.
핵심 포인트
- AI 최적화 요청 시 50%의 확률로 성능 저하 발생
- 코드의 외관(리팩토링)과 실행 속도는 상관관계가 낮음
- 성능 개선은 주로 시간 복잡도(Complexity)를 낮출 때 발생
- AI가 제안한 라이브러리나 문법이 항상 더 빠른 것은 아님
먼저 결론부터 말씀드립니다. AI에게 "이 코드, 속도 높여줘"라고 부탁해서 나온 10개를 실측해 본 결과, 빨라진 것은 3개뿐이었습니다. 2개는 오차 범위 내에서 변함이 없었고, 나머지 5개는 오히려 느려졌습니다. 절반이 최적화 (Optimization)를 부탁한 결과로서 느려진 것입니다.
"AI에게 최적화를 시키면 빨라질 것이다"라고 저는 막연히 믿고 있었습니다. 코드는 확실히 "그럴싸하게" 바뀝니다. List Comprehension (리스트 컴프리헨션)이 적용되고, 라이브러리가 도입되며, 외관은 현대적으로 변합니다. 하지만 스톱워치를 대보니 이야기가 달라졌습니다.
계기는 어떤 함수를 AI에게 최적화해 달라고 한 뒤, 왠지 모르게 체감 속도가 무거워졌기 때문입니다. "기분 탓인가" 싶어 측정해 보니 정말로 느려져 있었습니다. 그렇다면 다른 코드들은 어떨까 싶어 10개를 한꺼번에 검증한 것이 이 기사입니다. before/after를 하나씩 측정한 소박한 기록입니다.
먼저 선을 그어두겠습니다. AI에게 리팩토링 (Refactoring)을 부탁할 때 곤란한 문제는 이전에도 있었습니다. "적당히 다듬어줘"라고 말하면 요청하지도 않은 Decimal 타입이나 dataclass가 늘어나는 식의 품질과 설계의 폭주입니다.
이 기사는 그것과는 다른 축입니다. 다루는 것은 외관이나 설계가 아니라 실행 속도 그 자체입니다. "속도 높여줘"라고 명시적으로 부탁했는데, 측정해 보니 느려져 있었다. 그 부분만을 숫자로 추적합니다.
숫자를 내기 전에 조건을 명시합니다. 추측값은 단 하나도 없습니다.
- 머신: MacBook Pro (M3, 메모리 24GB)
- Python: 3.12.3
- 측정:
timeit으로 각 1,000회 실행하여 중앙값 (Median) 채택 - 메모리:
tracemalloc의 피크 (Peak) 값 - 대상: 제가 실무나 검증에서 작성한 기존 함수 10개
- 절차: 각 함수를 하나씩 제시하며 "동작을 바꾸지 말고 고속화해줘"라고만 지시
동일한 프롬프트 (Prompt), 동일한 데이터, 동일한 머신에서 before/after를 측정했습니다. AI 모델은 2026년 6월 시점의 주요 코딩용 모델을 사용하고 있습니다.
실행 시간의 중앙값입니다. 짧을수록 빠르다는 것을 의미합니다.
| # | 원본 코드 내용 | AI의 최적화 방침 | before | after | 판정 |
|---|---|---|---|---|---|
| 1 | CSV를 수동 루프로 집계 | pandas로 교체 | 12ms | 45ms | 저하 |
| ... | +=로 문자열 연결 | "".join()으로 변경 | 56ms | 6ms | 개선 |
| 5 | 순차 처리 | threading으로 병렬화 | 220ms | 260ms | 저하 |
| 6 | 단순 재귀 | 메모이제이션 (Memoization) 추가 | 1,200ms | 18ms | 개선 |
| ... |
개선 3개, 불변 2개, 저하 5개. 최적화를 부탁했는데 절반이 느려졌습니다. 개선된 3개는 확실히 차원이 다르게 빨라졌기 때문에, 평균만 보면 빨라진 것처럼 착각할 수 있습니다. 하지만 하나씩 살펴보면 절반은 오히려 느려졌습니다.
"최적화했다"라는 AI의 설명문과 실제 실행 시간은 별개입니다. 코드가 깔끔해지는 것과 빨라지는 것은 전혀 상관관계가 없었습니다.
개선된 3개(#3, #4, #6)를 보면 공통점이 하나 있습니다. 모두 계산량 (Complexity) 자체를 낮춘 케이스입니다.
이중 루프(#3)는 $O(n^2)$를 딕셔너리 조회인 $O(n)$으로 만들었습니다. 문자열 연결(#4)은 +=를 할 때마다 새로운 문자열을 만드는 $O(n^2)$를 일괄적인 join으로 바꿨습니다. 재귀(#6)는 동일한 계산의 반복을 메모이제이션으로 없앴습니다.
예를 들어 #3은 다음과 같은 변환이었습니다.
# before: O(n^2) 매번 리스트를 선형 탐색
result = []
for order in orders:
...
이것은 빨라지는 것이 당연합니다. 탐색 횟수 자체가 줄어들었기 때문입니다. AI가 정말로 효과적인 최적화를 하는 것은 이처럼 알고리즘의 계산량을 한 단계 낮출 수 있을 때였습니다. 340ms가 11ms가 되거나(#3), 1,200ms가 18ms가 되는(#6) 것과 같은 차원이 다른 개선은 여기서만 일어났습니다.
반대로 말하면, 계산량이 변하지 않는 코드 수정은 빨라질 이유가 애초에 없습니다. AI는 그 부분을 구분하지 않고 "최적화 안"을 내놓습니다.
문제는 저하된 5개입니다. 이것도 공통점이 명확했습니다. "빨라질 것 같은 도구"를 가져다 놓기만 한 케이스입니다.
pandas(#1)도 numpy(#8)도 대량의 데이터라면 빠른 도구입니다. 하지만 작은 데이터에서는 라이브러리를 불러오고 데이터를 변환하는 비용이 계산 본체를 상회합니다. 0.9ms의 처리에 배열로의 변환만으로 수 ms를 더한 셈입니다. 도구가 나쁜 것이 아니라, 규모에 맞지 않는 것입니다.
numpy화(#8)는 다음과 같은 코드 변경이었습니다.
# before: 작은 리스트의 단순 합계
total = sum(x * 2 for x in values) # values는 20개 요소 정도
# after: numpy 배열로 변환한 후 계산
...
20개 요소의 리스트에 대해 굳이 numpy 배열을 만드는 비용이 더 높게 들었습니다. numpy가 효과를 발휘하는 것은 수만 개 요소부터입니다.
threading을 이용한 병렬화(#5)는 더욱 명확한 실패 사례입니다. Python에는 GIL (Global Interpreter Lock)이 있어, CPU를 사용하는 처리에서는 스레드를 늘려도 동시에 동작할 수 없습니다. 실제로는 하나의 스레드만 계산할 수 있는데, 스레드를 생성하고 전환하는 비용만 추가됩니다. 병렬화는커녕 그만큼 더 느려졌습니다. CPU-bound 처리를 진정으로 병렬화하고 싶다면, threading이 아니라 multiprocessing이나 프로세스 풀 (Process Pool)이 필요합니다. AI는 이 부분을 착각했습니다.
itertools화(#10)는 "Pythonic하고 아름다운" 코드였습니다. 하지만 map이나 filter의 함수 호출 계층이 늘어나, 단순한 for 루프보다 느려졌습니다. Python에서는 함수 호출 자체에 비용이 발생하기 때문입니다. 아름다움과 속도는 여기서도 별개의 문제였습니다.
AI는 "일반적으로 빠르다고 여겨지는 수법"을 알고 있습니다. 하지만 눈앞의 데이터 규모나 실행 환경에서 그것이 정말 빠른지는 실제로 측정해 보지 않으면 알 수 없습니다. AI는 측정하지 않고 "정석"을 제시합니다.
느려진 것만큼이나 함정이었던 것은, 변화가 없었던 2개(#7, #9)입니다.
dataclass에 __slots__를 추가하는 것(#7)도, 중첩된 if문의 조기 반환 (Early Return)화(#9)도, 흔히 "빨라진다" 혹은 "깔끔해진다"라고 소개되는 수법입니다. 실제로 __slots__는 메모리를 약간 줄여주었습니다. 하지만 실행 시간은 거의 변하지 않았습니다. 조기 반환은 가독성은 높였지만 속도와는 무관했습니다.
여기서 알 수 있는 것은, 가독성 개선과 속도 개선은 완전히 별개라는 점입니다. AI는 이 둘을 "최적화"라는 단어로 묶어서 제안합니다. 받아들이는 쪽에서 그것이 읽기 편함에 대한 이야기인지, 속도에 대한 이야기인지를 구분하지 않으면 기대치가 어긋나게 됩니다. 조기 반환은 넣어도 좋습니다. 단, "빨라지니까"가 아니라 "읽기 편해지니까"라는 이유여야 합니다.
그 이유는 AI가 학습하고 있는 것이 "텍스트로서의 정석"이기 때문이라고 저는 생각합니다.
"루프보다 리스트 컴프리헨션(List Comprehension)", "순차 처리보다 병렬화", "직접 구현보다 라이브러리". 이러한 일반론은 세상의 수많은 기사에 적혀 있습니다. AI는 그것을 정확하게 재현합니다. 하지만 그 정석이 성립하는 전제 조건(데이터 규모, CPU-bound인지 IO-bound인지)까지는 눈앞의 코드에서 읽어내지 못합니다.
또 다른 이유는 AI가 실행 환경을 가지고 있지 않다는 점입니다. 우리는 "측정하고 말해"라고 할 수 있지만, AI는 대부분의 경우 코드를 실행하지 않고 겉모습만 보고 "이것은 빠를 것 같다"라고 판단합니다. 요리의 맛을 보지 않고 레시피만 보고 "맛있을 것이다"라고 말하는 것과 같습니다. 그렇기에 실행과 측정은 인간 측이 맡아야 합니다.
2026년에 들어서며 이 문제는 연구 분야에서도 정면으로 다뤄지기 시작했습니다. LLM이 생성한 코드의 실행 효율을 측정하는 벤치마크(SWE-fficiency 등)나, 생성된 코드의 소비 전력을 측정하는 연구가 나오고 있습니다. "AI는 동작하는 코드를 작성한다"는 단계는 끝났고, "그 코드가 빠른가, 아니면 에너지 효율적인가"가 다음 논점이 되고 있습니다.
저의 결론은, AI의 최적화를 믿지 마라는 것이 아닙니다. 측정하고 나서 채택하라는 것입니다.
구체적으로 저는 세 가지를 습관화했습니다.
- 최적화를 요청할 때는 "정석이 아니라, 이 데이터 규모에서 빠른 안을"이라며 조건을 전달한다.
- AI에게 최적화 안과 함께 측정 코드(
timeit)도 작성하게 한다. - before/after를 반드시 실행하여, 숫자가 개선된 안만 채택한다.
특히 두 번째 방법이 효과적이었습니다. 프롬프트를 이렇게 바꾸는 것만으로도 결과가 달라집니다.
# 약한 프롬프트 (정석을 가져옴)
이 코드를 고속화해줘.
# 강한 프롬프트 (측정하게 함)
...
「데이터는 몇 건 정도인가」를 전달하면, AI가 pandas나 numpy와 같은 대규모 데이터용 도구를 스스로 사용하지 않는 경우가 있었습니다. 데이터 규모는 코드만으로는 읽어낼 수 없기에, 인간이 알려줄 수밖에 없는 정보입니다.
그리고 측정 코드를 함께 작성하게 하면, AI 스스로가 "생각보다 빨라지지 않았습니다"라고 인정하는 사례가 나옵니다. 측정하는 습관을 AI에게도 갖게 하는 것입니다.
또 하나, 측정 그 자체에 대한 주의점이 있습니다. 단 한 번만 측정하면, 워밍업 (Warm-up)이나 캐시 (Cache)의 영향으로 결과가 흔들립니다. 제가 timeit으로 1,000번 실행하여 중앙값을 취한 것은 이러한 변동성을 없애기 위해서입니다. 단 한 번의 실행으로 "빨라졌다"고 판단하면, 오차를 개선으로 착각하게 됩니다.
이번 10개의 사례를 통해, 채택하기 전에 확인하면 좋은 간단한 기준이 보였습니다.
| AI의 제안 | 빨라지기 쉬운가 |
|---|---|
| 계산량(Complexity)을 낮춤 (O(n²)→O(n) 등) | 빨라짐 |
| ... |
"계산량이 낮아졌는가"를 하나 확인하는 것만으로도, 채택해야 할 제안인지 아닌지 가늠할 수 있습니다. 낮아지지 않았다면 빨라질 이유를 의심해 보는 것. 이것만으로도 판단의 정밀도가 높아졌습니다.
엔지니어의 업무는 현상을 올바르게 분석하고, 올바른 방향으로 노력하는 것이라고 저는 생각합니다. AI의 최적화도 마찬가지입니다. "빨라진 것 같다"는 느낌에서 멈추지 말고, 숫자로 현상을 확인해야 합니다. 그 과정을 건너뛰면, 절반의 확률로 반대 방향으로 달리게 됩니다.
만약을 위해 보충하자면, 이것은 AI를 사용할 수 없다는 이야기가 아닙니다. #3이나 #6처럼 계산량을 낮추는 최적화는 AI가 더 빠르고 정확하게 작성할 수 있습니다. 제가 말하고 싶은 것은, AI의 제안을 "채택할지 말지"에 대한 판단은 인간이 쥐고 있어야 한다는 것입니다. 제안하게 하는 것은 AI, 채택 여부를 결정하는 것은 측정 결과. 이렇게 역할 분담을 하고 나서부터는 최적화로 인해 오히려 느려지는 실수가 사라졌습니다.
- AI에게 최적화를 시킨 10개 중, 빨라진 것은 3개뿐. 5개는 오히려 느려졌다
- 빨라진 것은 계산량(O(n²)→O(n))을 낮춘 케이스뿐
- 느려진 것은 규모에 맞지 않는 라이브러리 도입, GIL 하에서의 병렬화, Pythonic화
- AI는 "텍스트로서의 정석"을 맞추지만, 데이터 규모나 실행 환경까지는 보지 않는다
- 대책은 하나. 최적화 안과 측정 코드를 세트로 출력하게 하고, 숫자가 개선된 안만 채택한다
코드가 깔끔하게 다시 작성되면, 무심코 빨라졌다는 기분이 듭니다. 하지만 속도는 스톱워치가 결정합니다. 재미있게 접근해 봅시다.
AI와의 협업을 코드의 속도뿐만 아니라 하루의 개발 플로우 전체로 다시 설계하는 이야기는, 이곳에 정리해 두었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기