perf(提交): 格式化前送判题机编的那一下改成排队,一个班同时交也不会把判题机挤到人人超时
Deploy / deploy (push) Canceled after 0s

格式化前的编译检查不走判题队列,原来来多少份就同时往判题机上压多少份。服务器只有两核,
按两核实测 40 份 C++ 同时压上去,每份都撞 8 秒超时,正式判题也跟着变慢。现在同时最多
2 份,其余排队,8 秒是连排队带编译的总预算,排不上就当编得过、照常格式化。

同样 40 份,现在 5.2 秒全部编完、判断全对;压到 80 份时有 24 份等满 8 秒放弃。上一个提交
之后,编得过的代码只有 1~2% 还会走到这一步,平时基本排不起队。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-14 12:24:07 +08:00
1 parent 797b41751e
commit cff989bf19
1 file changed
+32 -1
+32 -1
View File
@@ -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<boolean>((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--
}
}