Skip to content

评测模型 ​

一句话:每次提交同时启动 Evaluator 容器(跑出题人的 evaluate.py)与 Solution 容器(跑用户代码 + Solution Host 进程),由 Evaluator 主动调用用户函数并按返回值判分。

Neuro OJ 当前支持双容器评测模型。每次提交会同时涉及 Evaluator 容器和 Solution 容器。核心术语见术语表。

Solution Host 与 Solution 容器

Solution 容器是 Docker 容器;Solution Host 是其中负责加载用户模块、转发函数调用的协议进程(即 noj_solution_sdk.host)。下文按此区分使用。

与传统 OJ 的差异 ​

传统 OJ 通常运行用户程序,把 stdin 输入喂给程序,再比对 stdout。Neuro OJ 的 Python 题目不使用这种答案通道:

  • 用户提交的是可被调用的 Python 代码。
  • 题面会声明必须实现的函数,例如 solve(a, b)。
  • evaluate.py 按题目自己的方式读取测试数据或生成测试输入,调用用户函数,并决定是否通过。
  • 用户代码的 print() 不是答案输出;当前实现中普通 print() 写到 Solution stdout 会被协议层丢弃,不应依赖它作为调试回传通道。

Evaluator 容器 ​

Evaluator 容器运行出题人提供的 evaluate.py。它能读取纯净评测包中的测试数据和辅助文件,也可以自行生成测试输入或调用本地辅助逻辑,并通过 noj_evaluator_sdk 调用 Solution。

Evaluator 是评分逻辑的所有者。它决定:

  • 调用哪个函数。
  • 给函数传什么参数。
  • 如何比较返回值。
  • 如何计算分数。
  • 向用户展示哪些详情。

Evaluator 的两个输出通道去向不同

  • stdout:进入评测输出,同时承载 NDJSON 协议帧与 ---RESULT--- 标记;Judge Worker 解析带 type 字段的协议帧,其余文本作为评测输出。
  • stderr:只作为普通日志/诊断输出,不承载 RPC 帧。

Solution 容器 ​

Solution 容器运行用户提交的代码(Judge Worker 以硬编码名 main.py 注入)和 Solution Host。Solution Host 会加载用户模块、自动注册其中的顶层函数,并等待 Evaluator 发起函数调用。

调用失败时 Solution Host 返回错误帧,Evaluator SDK 将其转换为对应异常:

情况协议 codeEvaluator 侧异常
用户函数不存在NotFoundNotFoundError
用户函数抛异常Exception(含清洗后 traceback)SystemError
返回值类型非法RejectedRejectedError

调用失败 ≠ 提交失败

上表说的是发回给 Evaluator 的调用错误对象,不等于最终提交结果(verdict)。新协议下最终状态只保留 finished / error,分数是唯一结果;Accepted / WrongAnswer 等只作为 details.cases 用例级参考信息。

具体来说:

  • 用户函数抛异常后,Evaluator 可以把它记为失败用例,最终通常为 finished + 0 分。
  • 调用超时或调用阶段资源异常后,Evaluator 也可以把它当作普通失败用例处理,最终为 finished + 0 分。
  • 只有当 Evaluator 自身异常退出、整体超时,或 Solution Host 在调用前就无法正常工作时,最终状态才会是 error。
  • 用户代码语法错误、模块导入失败、Solution Host 启动失败,通常会在调用前被判为 error,因为这时 Evaluator 还没有拿到可继续评分的函数实例。

超时与状态映射 ​

两层超时的最终状态映射:

超时来源触发最终状态
evaluator 整体执行超时评测总时长超过 time_limit_mserror(Judge Worker 强制终止,做题人不可通过改代码解决)
单次调用超时且 evaluator 未捕获调用超过 call_timeout_ms,evaluate.py 异常退出、无 ---RESULT---error
单次调用超时且 evaluator 捕获同上,但 evaluator 记为失败用例由 evaluator 决定(通常为 finished + 0 分)
evaluator 异常退出且从未发生调用超时evaluate.py 自身 bug、环境问题、无 ---RESULT---error

evaluator 启动超时(评测环境未就绪)同样归 error。

Solution Host 在同一次评测中是常驻的

多次 runner.call() 默认调用同一个 Python 模块实例,因此用户模块的全局状态会在调用之间保留。当前 SDK 不提供 runner.restart()。

隔离边界 ​

Solution 不应直接读取隐藏用例。隐藏用例的数据位于 Evaluator 读取的纯净评测包中,或由 Evaluator 在运行时生成,由 Evaluator 控制使用方式。

网络、内存、时间和进程数限制由 Judge Worker 和运行时配置控制。出题人应避免在 evaluator 中泄露隐藏用例内容。

调用链路 ​

一次 runner.call("solve", 1, 2) 的链路是:

出题人正常情况下只使用 SolutionRunner,不需要手写 RPC 帧。RPC 细节见 RPC 与可传递数据。

Neuro OJ 是一个独立社区项目,与 CCF、LMCC、IOAI 及 NOAI 无官方关系。