[Part 3.] Web Worker를 UI 응답성 기준으로 다시 검증하기

전체 생성 시간이 아니라 UI 루프 지연을 비교해 Web Worker를 유지할 근거와 아직 남은 불확실성을 정리합니다.

#performance#thumbnail#web-worker#webcodecs

1. 구조를 만든 뒤 Web Worker가 정말 필요한지 의심했다

앞선 두 글에서 썸네일 생성 과정을 세 단계로 나눴다.

  1. poster 한 장으로 import 직후의 빈 화면을 대체한다.
  2. 현재 viewport의 visible tile을 먼저 채운다.
  3. 화면 밖 프레임은 낮은 우선순위로 prefetch한다.

역할을 나누고 보니 Worker 메시지, 취소 처리, stale result 검사, 메모리 정리까지 관리해야 했다. 직접 에디터를 사용했을 때 큰 불편이 느껴지지 않자 새로운 질문이 생겼다.

이 복잡도를 감수하면서 Web Worker를 유지해야 하는가?

이 질문에 답하려면 “Worker가 더 빠른가?”만 봐서는 부족했다. 내가 확인하려는 것은 썸네일 생성 중에도 스크롤과 드래그를 처리할 UI 루프가 유지되는가였다.

이번 측정에서 확인한 결론은 제한적이다.

  • 100장 생성에서 Worker/WebCodecs와 Main/WebCodecs의 전체 시간 차이는 작았다.
  • 같은 측정에서 Worker 경로의 UI 루프 지연 대리 지표는 더 낮았다.
  • 따라서 현재 수치만 보면 Worker를 제거하는 것보다 유지하는 판단이 타당했다.
  • 다만 별도 벤치마크 결과이므로 실제 에디터의 드래그 응답성까지 증명하지는 않는다.

2. “써보니 괜찮다”로 판단할 수 있는 범위를 구분했다

수동 검증은 제품 사용 경험을 직접 확인한다는 점에서 중요하다. import 직후 스크롤하고, 비디오 구간을 드래그하고, trim을 조작했는데 불편하지 않았다면 현재 UX가 심각하게 깨져 보이지 않는다는 근거가 된다.

하지만 그 관찰만으로 모든 조건의 성능을 결론 낼 수는 없다.

수동 검증으로 판단할 수 있는 것추가 측정이 필요한 것
현재 시나리오에서 눈에 띄는 불편이 있었는가낮은 사양과 대용량 영상에서도 안전한가
기능이 기대한 순서로 동작하는가Worker를 제거해도 UI 지연이 같게 유지되는가
추가 최적화가 당장 필요한가메모리 증가나 장시간 누수가 없는가

즉 “현재 사용감이 괜찮다”는 관찰은 최적화의 우선순위를 낮출 근거가 될 수 있다. 그러나 기존 경로를 제거할 충분조건은 아니다.

3. 생성 속도를 세 가지 질문으로 다시 나눴다

처음에는 요청한 썸네일이 모두 준비되는 시간만 비교했다. 하지만 “빠르다”는 표현에는 서로 다른 세 결과가 들어 있었다.

기준의미주로 영향을 주는 선택
첫 시각적 피드백import 후 첫 이미지가 나타나는 시간poster-first
전체 생성 시간요청한 프레임이 모두 준비되는 시간디코딩 경로와 작업량
UI 응답성생성 중 입력과 화면 갱신이 지연되는 정도메인 스레드 작업량

Part 1에서 첫 비디오 구간 표시 시간은 Worker 우선 6,262.2ms에서 poster 우선 2,815.8ms로 약 55% 줄었다. 이 변화는 Worker 자체의 효과라고 볼 수 없다. 전체 결과를 기다리지 않고 대표 이미지 한 장을 먼저 표시한 작업 순서 변경의 효과에 가깝다.

Web Worker의 필요성을 판단하려면 세 번째 기준, 즉 UI 응답성을 따로 봐야 했다.

4. WebCodecs와 Worker의 효과를 분리했다

Part 1에서는 HTMLVideoElement seek와 Worker/WebCodecs를 비교했다. 이 비교만으로는 Worker 경로가 빨랐던 이유를 분리하기 어렵다. 실행 위치뿐 아니라 디코딩 API도 다르기 때문이다.

그래서 WebCodecs 파이프라인을 메인 스레드에서도 실행하는 비교군을 추가했다.

경로처리 흐름JavaScript 실행 위치비교 목적
HTMLVideoElement seekcurrentTime 변경 후 frame capture메인 스레드에서 요청, 디코딩 완료는 이벤트로 대기브라우저 비디오 요소 경로의 특성 확인
Main/WebCodecsArrayBuffer 읽기 → MP4 demux → VideoDecoder 호출Window의 메인 스레드WebCodecs 파이프라인 제어 비용 확인
Worker/WebCodecsArrayBuffer 읽기 → MP4 demux → VideoDecoder 호출Web Worker같은 처리 흐름을 별도 스레드로 옮긴 효과 확인

Main/WebCodecs와 Worker/WebCodecs는 가능한 한 같은 demux·decode 요청 흐름을 사용했다. 두 경로의 주요 차이를 JavaScript 실행 위치로 좁히기 위한 비교다. VideoDecoder의 내부 디코딩이 전부 해당 JavaScript 스레드에서 실행된다는 뜻은 아니다. 브라우저 내부 스케줄링과 ImageBitmap 전달 같은 차이까지 완전히 제거한 실험도 아니다.

5. UI 응답성은 Main busy와 Max stall로 추정했다

UI 응답성을 보기 위해 requestAnimationFrame 간격을 기록했다. 여기서 사용한 두 지표는 브라우저 표준 지표가 아니라 이 테스트에서 정의한 측정값이다.

5-1. Main busy

Main busy는 측정 중 requestAnimationFrame 간격이 16.7ms를 넘긴 지연 시간을 누적해 전체 측정 시간과 비교한 비율이다. 16.7ms는 60Hz 화면에서 한 프레임에 해당하는 시간이다.

이 값에는 JavaScript 실행만 들어가지 않는다. rendering, garbage collection, ImageBitmap 수신과 반영, 브라우저 내부 작업이 함께 영향을 줄 수 있다.

따라서 Main busy는 메인 스레드 JavaScript 실행 시간이 아니라, UI 루프 지연을 추정하는 대리 지표다.

5-2. Max stall

Max stall은 측정 구간에서 관찰한 가장 긴 단일 requestAnimationFrame 간격이다. 값이 크면 해당 구간에서 화면 갱신 기회가 오래 오지 않았다는 뜻이다.

이 값만으로 사용자가 정확히 같은 길이의 멈춤을 체감했다고 단정할 수는 없다. 다만 경로별로 가장 긴 UI 루프 지연을 비교하는 데 사용할 수 있다.

같은 비디오 파일에서 각 경로로 1장, 10장, 100장을 요청했다. 반복 횟수와 결과 분산은 기록하지 못했으므로, 아래 수치를 다른 환경의 일반적인 성능으로 확대 해석하지 않는다.

같은 비디오 파일에서 세 경로로 1장, 10장, 100장을 요청한 측정 화면

6. 전체 시간은 비슷했지만 UI 루프 지연은 달랐다

100장을 생성한 한 번의 기록은 다음과 같았다.

경로전체 생성장당 평균Main busyMax stall
Worker/WebCodecs3,936.61ms39.37ms11%428.87ms
Main/WebCodecs4,047.95ms40.48ms66%1,251.81ms
HTMLVideoElement seek20,844.48ms208.44ms0%21.05ms

Worker/WebCodecs와 Main/WebCodecs의 전체 생성 시간 차이는 약 111ms, 비율로는 약 2.8%였다. 반복 측정의 분산이 없으므로 Worker가 전체 생성에서 일반적으로 더 빠르다고 결론 내리기에는 근거가 부족하다.

반면 같은 기록에서 Main busy는 66%에서 11%로 55%포인트 낮았고, Max stall은 1,251.81ms에서 428.87ms로 약 65.7% 낮았다. 이 차이는 MP4 demux와 WebCodecs 파이프라인 제어를 Web Worker로 옮겼을 때 UI 루프 지연이 감소한다는 해석과 일치한다.

HTMLVideoElement seek는 전체 생성이 가장 오래 걸렸지만 Main busy와 Max stall은 가장 낮았다. currentTime을 변경한 뒤 이벤트를 기다리는 시간이 길어도, 그 대기 전체가 메인 스레드를 계속 점유하는 것은 아니기 때문이다. 전체 처리 시간이 길다는 사실과 UI 루프를 오래 막는다는 사실은 같지 않았다.

이 결과로 Web Worker의 역할을 다시 정의했다.

현재 측정에서 Web Worker의 주된 가치는 전체 생성 시간 단축보다 UI 루프 지연을 줄이는 데 있었다.

7. 대표 이미지 한 장에는 seek가 분명히 유리했다

한 장만 요청했을 때는 결과가 크게 달랐다.

경로첫 프레임전체 생성
HTMLVideoElement seek50.29ms51.20ms
Worker/WebCodecs3,163.29ms3,163.35ms
Main/WebCodecs6,143.84ms6,143.85ms

이 기록에서는 poster 한 장을 만드는 데 HTMLVideoElement seek가 가장 빨랐다. WebCodecs 경로는 파일 읽기, demux, decoder 준비 비용을 한 장에도 지불해야 했기 때문이다.

다만 seek를 여러 장에 사용할 때는 결과가 안정적이지 않았다. 10장 실행에서 전체 시간은 912,348.63ms, Max stall은 909,557ms였다. 다른 실행과 차이가 지나치게 커서 일반적인 성능 값으로 사용할 수 없었다.

원인은 확인하지 못했다. 가능한 설명으로는 seek queue 정지, 브라우저 decoder 지연, 백그라운드 탭 제한, 측정 코드 문제가 남아 있다. 원인을 구분하려면 반복 실행, timeout 로그, 각 seek의 시작·완료 시각, Performance trace가 필요하다.

따라서 이 이상치만으로 “여러 장의 seek는 항상 느리다”고 결론 내리지 않았다. Part 2에서 제안한 visible tile의 queued sequential seek도 이 결과만으로는 검증되지 않았다.

현재 증거가 지지하는 범위는 다음과 같다.

작업현재 판단
poster 1장HTMLVideoElement seek 사용 근거가 충분함
visible tile 소량seek 또는 Worker 중 어느 쪽이 나은지 실제 UI 비교 필요
대량 썸네일Worker/WebCodecs 유지 근거가 있음
Main/WebCodecs 단독 전환현재 기록에서는 UI 루프 지연이 커 보임

8. 별도 벤치마크가 실제 편집 경험을 증명하지는 않는다

테스트 페이지는 디코딩 경로를 통제해서 비교하기 좋다. 하지만 실제 에디터에서 비디오 구간을 드래그할 때는 썸네일 외의 작업도 함께 실행된다.

  • drag-and-drop 좌표 계산
  • preview state 갱신
  • Canvas redraw
  • 드래그 완료 후 프로젝트 상태 반영

따라서 벤치마크의 Main busy 차이만으로 “실제 드래그가 Worker 때문에 부드러워졌다”고 말할 수 없다. 실제 제품에서 인과 범위를 더 좁히려면 같은 시나리오를 세 비교군으로 실행해야 한다.

비교군확인하려는 것
Worker/WebCodecs현재 구조의 편집 응답성
Main/WebCodecsWorker를 제거했을 때의 변화
thumbnail 생성 끔타임라인 자체 rendering 비용의 기준선

확인할 시나리오도 동일해야 한다.

  1. import 직후 썸네일 생성 중 drag
  2. 썸네일 생성 완료 후 drag
  3. zoom 단계별 drag
  4. 비디오 구간 수를 늘린 상태의 drag
  5. trim handle drag

이 E2E 비교는 이번 글에서 완료하지 못했다. 따라서 별도 벤치마크에서는 Worker 경로의 UI 루프 지연이 낮았다는 결론과 실제 에디터에서도 사용자 입력 지연이 줄었다는 결론을 구분한다.

9. Worker를 유지하면 메모리 관리도 함께 유지해야 한다

Web Worker는 demux와 decode를 메인 스레드 밖에서 실행하지만, 생성된 ImageBitmap과 cache의 수명까지 자동으로 관리하지 않는다. 화면 밖 프레임을 무제한으로 prefetch하거나 결과를 한 번에 전달하면 메모리 사용량이 커질 수 있다.

필요한 방어선은 다음과 같다.

방어선막으려는 상황
batch 전송많은 ImageBitmap이 한 번에 도착하는 상황
cache 상한긴 영상에서 프레임이 계속 누적되는 상황
in-flight deduplication같은 timestamp를 중복 생성하는 상황
stale result 폐기스크롤·줌 뒤 늦게 도착한 결과가 현재 화면을 덮는 상황
ImageBitmap.close()사용하지 않는 bitmap 리소스가 남는 상황
abort 처리import 취소, undo, 프로젝트 전환 뒤 작업이 계속되는 상황

이 항목들은 메모리 누수가 실제로 측정됐다는 뜻이 아니다. Worker를 유지할 때 검증해야 하는 자원 수명 관리 조건이다. 반복 import 전후 heap snapshot과 ImageBitmap 해제 시점을 확인해야 누수 여부를 판단할 수 있다.

10. 현재 선택은 Worker 유지지만 조건부다

현재까지의 측정과 미정 범위를 함께 놓으면 다음과 같다.

선택근거감수하는 비용
poster-first 유지한 장 seek가 세 경로 중 가장 빨랐음poster와 실제 thumbnail cache 분리
Worker/WebCodecs 유지Main/WebCodecs보다 Main busy와 Max stall이 낮았음메시지, 취소, stale result, 메모리 관리
seek는 poster에 우선 사용한 장 생성 결과가 명확했음여러 장 seek의 이상치 원인 미확인
background prefetch에 상한 적용화면 밖 작업은 필수 완료 작업이 아님상한값 조정 필요
실제 UI E2E를 후속 검증별도 벤치마크의 적용 범위가 제한적임비교 환경과 시나리오 관리 필요

이 선택은 Web Worker가 언제나 최선이라는 결론이 아니다. 현재 비교에서 Worker를 제거할 근거보다 유지할 근거가 더 강하다는 뜻이다.

11. 어떤 증거가 나오면 결정을 다시 바꿀 것인가

성능 구조는 복잡도가 있으므로 재검토 조건을 미리 정해야 한다.

남은 질문필요한 증거결정에 미치는 영향
실제 에디터에서도 차이가 있는가세 비교군의 동일 E2E 결과차이가 작으면 Worker 제거 재검토
저사양·4K·긴 영상에서도 같은가환경별 반복 측정과 분산적용 조건 또는 fallback 조정
seek 10장 이상치의 원인은 무엇인가timestamp별 timeout과 decoder 로그visible tile 경로 재선택
반복 import에서 자원이 해제되는가heap snapshot과 bitmap 수명 추적cache·abort 정책 보강
prefetch 상한이 적절한가영상 길이와 viewport 이동 패턴별 cache 관찰batch와 cache 상한 조정

현재 결론을 가장 정확하게 표현하면 다음과 같다.

이번 벤치마크에서는 Worker/WebCodecs가 Main/WebCodecs보다 UI 루프 지연 대리 지표가 낮았다. 실제 에디터 E2E와 메모리 검증이 끝나기 전까지는 Worker를 유지한다.

12. 최적화의 기준이 처리량에서 사용자 대기 단계로 바뀌었다

세 번의 시도를 거치며 판단 기준이 계속 좁아졌다.

  1. 처음에는 Web Worker가 전체 생성 시간을 줄이는지 물었다.
  2. 다음에는 사용자가 보고 있는 viewport를 먼저 채우는 방법을 물었다.
  3. 마지막에는 Worker가 실제로 보호해야 하는 자원이 UI 루프인지 물었다.

이 과정에서 같은 “속도”라는 단어로 묶었던 값들이 서로 다른 질문에 답한다는 것을 알게 됐다.

  • poster 표시 시간은 첫 시각적 피드백을 설명한다.
  • 전체 생성 시간은 처리량을 설명한다.
  • Main busy와 Max stall은 UI 루프 지연을 추정한다.
  • E2E 입력 지연은 실제 편집 경험을 검증한다.

하나의 지표가 좋아졌다고 다른 지표까지 좋아졌다고 말할 수 없다. 반대로 구조가 복잡하다는 이유만으로, 측정에서 확인된 응답성 보호 효과를 바로 제거해서도 안 된다.

성능 최적화는 가장 빠른 기술을 고르는 일이 아니라, 사용자가 기다리는 단계를 나누고 각 단계에 필요한 비용만 지불하는 일이었다.

    시리즈 바로가기썸네일 생성 최적화

    관련 글

    댓글 0

    닉네임과 댓글은 공개됩니다.

    0/1000

    댓글을 불러오는 중입니다…