feat(installer-rp): auto-tune music concurrency to CPU core count
os.cpus().length 기준 동시 다운로드 수를 자동 결정: - 2 코어 이하 → 2 동시 - 3~4 코어 → 3 동시 - 5~8 코어 → 4 동시 - 9 코어 이상 → 5 동시 (YouTube throttle 때문에 상한) 환경변수 MUSIC_CONCURRENCY 로 강제 오버라이드 가능(상한 8). 설치 로그에 감지된 코어 수와 선택된 동시성 노출. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import https from 'node:https'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import fsp from 'node:fs/promises'
|
import fsp from 'node:fs/promises'
|
||||||
|
import os from 'node:os'
|
||||||
import { URL } from 'node:url'
|
import { URL } from 'node:url'
|
||||||
import type { ChildProcess } from 'node:child_process'
|
import type { ChildProcess } from 'node:child_process'
|
||||||
import type { Manifest, PackDefinition, PackList } from '../shared/types.js'
|
import type { Manifest, PackDefinition, PackList } from '../shared/types.js'
|
||||||
@@ -27,8 +28,23 @@ interface RpInstallerState {
|
|||||||
activeChildren: Set<ChildProcess>
|
activeChildren: Set<ChildProcess>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 동시 yt-dlp 프로세스 수. 너무 높이면 유튜브가 throttle. */
|
/**
|
||||||
const MUSIC_CONCURRENCY = 3
|
* 동시 yt-dlp 프로세스 수를 CPU 코어 수로 자동 결정.
|
||||||
|
* - yt-dlp + ffmpeg 변환이 CPU 바운드라 코어 수가 가장 좋은 프록시.
|
||||||
|
* - 유튜브가 IP 단위로 throttle 걸기 때문에 5 이상은 효과 없음 → 상한 5.
|
||||||
|
* - 환경변수 MUSIC_CONCURRENCY 로 강제 오버라이드 가능.
|
||||||
|
*/
|
||||||
|
function pickMusicConcurrency(): number {
|
||||||
|
const override = Number(process.env.MUSIC_CONCURRENCY)
|
||||||
|
if (Number.isFinite(override) && override >= 1) {
|
||||||
|
return Math.min(8, Math.floor(override))
|
||||||
|
}
|
||||||
|
const cores = os.cpus()?.length ?? 4
|
||||||
|
if (cores <= 2) return 2
|
||||||
|
if (cores <= 4) return 3
|
||||||
|
if (cores <= 8) return 4
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_MANIFEST_URL = process.env.MANIFEST_URL ?? 'http://127.0.0.1:3000/manifest.json'
|
const DEFAULT_MANIFEST_URL = process.env.MANIFEST_URL ?? 'http://127.0.0.1:3000/manifest.json'
|
||||||
|
|
||||||
@@ -199,10 +215,13 @@ ipcMain.handle('rp:install:start', async (): Promise<{ resourcepackPath: string
|
|||||||
sendProgress({ phase: 'prep', message: '준비 완료', done: true })
|
sendProgress({ phase: 'prep', message: '준비 완료', done: true })
|
||||||
throwIfCancelled()
|
throwIfCancelled()
|
||||||
|
|
||||||
// 2-2. 음악 다운로드 (MUSIC_CONCURRENCY 개씩 병렬, ogg 변환)
|
// 2-2. 음악 다운로드 (CPU 코어 수 기반 자동 동시 다운로드, ogg 변환)
|
||||||
const musicDir = path.join(tempRoot, 'music')
|
const musicDir = path.join(tempRoot, 'music')
|
||||||
await fsp.mkdir(musicDir, { recursive: true })
|
await fsp.mkdir(musicDir, { recursive: true })
|
||||||
sendLog(`음악 다운로드 시작 (${musicTotal}곡, 동시 ${MUSIC_CONCURRENCY}개)`)
|
const concurrency = pickMusicConcurrency()
|
||||||
|
const cpuCount = os.cpus()?.length ?? 0
|
||||||
|
sendLog(`CPU 코어 ${cpuCount}개 감지 → 동시 다운로드 ${concurrency}개`)
|
||||||
|
sendLog(`음악 다운로드 시작 (${musicTotal}곡, 동시 ${concurrency}개)`)
|
||||||
|
|
||||||
// 클로저 안에서 narrowing 이 풀리지 않도록 로컬 alias.
|
// 클로저 안에서 narrowing 이 풀리지 않도록 로컬 alias.
|
||||||
const musicList = pack.list.music
|
const musicList = pack.list.music
|
||||||
@@ -252,7 +271,7 @@ ipcMain.handle('rp:install:start', async (): Promise<{ resourcepackPath: string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const workerCount = Math.min(MUSIC_CONCURRENCY, musicTotal)
|
const workerCount = Math.min(concurrency, musicTotal)
|
||||||
const workers: Promise<void>[] = []
|
const workers: Promise<void>[] = []
|
||||||
for (let w = 0; w < workerCount; w++) workers.push(musicWorker())
|
for (let w = 0; w < workerCount; w++) workers.push(musicWorker())
|
||||||
await Promise.all(workers)
|
await Promise.all(workers)
|
||||||
|
|||||||
Reference in New Issue
Block a user