From cff989bf19764c785eef98720f2893d128fe0aa4 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Wed, 14 Oct 2026 12:24:07 +0800 Subject: [PATCH] =?UTF-8?q?perf(=E6=8F=90=E4=BA=A4):=20=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E5=89=8D=E9=80=81=E5=88=A4=E9=A2=98=E6=9C=BA=E7=BC=96?= =?UTF-8?q?=E7=9A=84=E9=82=A3=E4=B8=80=E4=B8=8B=E6=94=B9=E6=88=90=E6=8E=92?= =?UTF-8?q?=E9=98=9F=EF=BC=8C=E4=B8=80=E4=B8=AA=E7=8F=AD=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E4=BA=A4=E4=B9=9F=E4=B8=8D=E4=BC=9A=E6=8A=8A=E5=88=A4=E9=A2=98?= =?UTF-8?q?=E6=9C=BA=E6=8C=A4=E5=88=B0=E4=BA=BA=E4=BA=BA=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 格式化前的编译检查不走判题队列,原来来多少份就同时往判题机上压多少份。服务器只有两核, 按两核实测 40 份 C++ 同时压上去,每份都撞 8 秒超时,正式判题也跟着变慢。现在同时最多 2 份,其余排队,8 秒是连排队带编译的总预算,排不上就当编得过、照常格式化。 同样 40 份,现在 5.2 秒全部编完、判断全对;压到 80 份时有 24 份等满 8 秒放弃。上一个提交 之后,编得过的代码只有 1~2% 还会走到这一步,平时基本排不起队。 Co-Authored-By: Claude Opus 5.5 --- apps/api/src/judge/run.ts | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/apps/api/src/judge/run.ts b/apps/api/src/judge/run.ts index 1680b83..483170b 100644 --- a/apps/api/src/judge/run.ts +++ b/apps/api/src/judge/run.ts @@ -120,16 +120,47 @@ export async function postJudge( * * 判题机只有 /judge 一个入口,得带一组测试点:给一组空输入,跑的那一下限 1 秒。 * 判题机连不上、超时,一律当编得过 —— 那就和原来一样照常格式化。 + * + * 这一下不进判题队列,所以自己排一道:同时最多 COMPILE_CHECK_CONCURRENCY 份在判题机上编, + * 其余等着。服务器只有两核,不排的话一个班 40 人一起交 C++ 能把判题机挤到每人 8 秒超时, + * 还拖慢正式判题。8 秒是连排队带编译的总预算,排不上也当编得过。 */ +const COMPILE_CHECK_CONCURRENCY = 2 +let compileChecks = 0 +const compileCheckWaiting: (() => void)[] = [] + export async function compileFails(language: string, source: string) { + const deadline = AbortSignal.timeout(8000) + if (compileChecks < COMPILE_CHECK_CONCURRENCY) { + compileChecks++ + } else { + const admitted = await new Promise((resolve) => { + const giveUp = () => { + compileCheckWaiting.splice(compileCheckWaiting.indexOf(wake), 1) + resolve(false) + } + const wake = () => { + deadline.removeEventListener("abort", giveUp) + resolve(true) + } + deadline.addEventListener("abort", giveUp, { once: true }) + compileCheckWaiting.push(wake) + }) + // 被叫醒时名额是直接转交过来的,compileChecks 不用再加 + if (!admitted) return false + } try { const response = await postJudge(language, source, 1000, 256, [{ input: "", output: "" }], { - signal: AbortSignal.timeout(8000), + signal: deadline, }) const body = (await response.json()) as JudgeResponse return body.err === "CompileError" } catch { return false + } finally { + const next = compileCheckWaiting.shift() + if (next) next() + else compileChecks-- } }