ZenML Pro 资源池实战示例手册:从 ResourceSettings 到抢占、队列与多池分配
【免费下载链接】zenmlZenML 🙏: One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml
本篇是 ZenML Pro 资源池(Resource Pool)功能的场景化实战手册,围绕"池(Pool)定义共享容量、策略(Policy)规定某个编排器/步骤执行器如何取用、步骤通过ResourceSettings声明需求"这三层模型展开。文中每个小节都是一个独立可复现的场景,逐一展示服务端在分配、排队、借用、抢占与拒绝时做出的决策。读完本文,你将能准确预测任意ResourceSettings+ 池容量 + 策略组合在 ZenML Pro 服务器端的最终结果,并能用zenml resource-pool/zenml resource-requestCLI 亲自验证。
资源池属于 ZenML 付费能力,且仅对动态流水线(dynamic pipelines)生效。建议先阅读同目录下的 资源池总览、核心概念 与 资源池对账(reconciliation)流程,再进入本手册。
阅读约定与默认假设
把本页当作一门短课程:每个小节是一个自洽的独立场景,你始终会看到三样东西——池(共享容量)、策略(某个编排器或步骤执行器如何取用该池)、步骤(ResourceSettings声明的需求),随后是服务端的具体行为。
除非另有说明,以下假设始终成立:
- 步骤默认是可抢占(preemptible)的,除非显式写
preemptible=False。这一默认值在源码中也得到确认:ResourceSettings.preemptible: bool = True(见 src/zenml/config/resource_settings.py)。 - 当我们说"没有其他工作在运行"时,意味着同一时刻只有一个步骤运行,方便你把注意力集中在单个决策上。
- 策略
reserved与limit里的每一个键,都必须存在于池的容量中。你无法在策略中计量池没有定义的资源。 - 如果一个编排器或步骤执行器绑定了多个池的策略,步骤仍然最多从一个池获得一次分配。整个请求必须在该池上完全合格;单个步骤的资源不会被拆到多个池。
reserved、limit、priority的精确定义见 核心概念;抢占的受害者排序规则见 How preemption works。
Primer:从ResourceSettings到资源请求
假设一个步骤声明如下:
from zenml.config import ResourceSettings ResourceSettings( gpu_count=2, cpu_count=4, memory="16GiB", pool_resources={"tensorrt_sessions": 1}, preemptible=True, )ZenML 会把它转换成一个资源请求,转换关系大致如下:
| 来源 | 请求键 | 数值如何推导 | 示例值 |
|---|---|---|---|
gpu_count | gpu | 与gpu_count相同 | 2 |
cpu_count | mcpu | ceil(cpu_count * 1000) | 4000 |
memory | memory_mb | 转换为 MB | 17180(对应"16GiB") |
pool_resources | (你的自定义名) | 原样拷贝,并与类型化字段合并 | 1 |
| 服务端 | step_run | 每个步骤恒为 1 | 1 |
这段转换逻辑在源码中可以直接看到:ResourceSettings.merged_requested_resources()方法会把gpu_count写入gpu键、把math.ceil(cpu_count * 1000)写入mcpu键、把内存换算成 MB 后向上取整写入memory_mb键,同时以pool_resources字典作为合并起点(见 src/zenml/config/resource_settings.py)。内存字符串的解析由ByteUnit枚举与MEMORY_REGEX负责校验(见 src/zenml/config/resource_settings.py),因此memory必须形如"16GiB"、"4GB"这类"数字+单位"的写法。
容量匹配规则:
- 池必须为
gpu、tensorrt_sessions这类有界键定义容量。 - 如果池里没有
mcpu、memory_mb、step_run的行,这三个维度在池层面是无界的(见下文示例)。 - 对于其他所有键,池中缺失行意味着容量为零:正向请求会被拒绝。
- 如果想让策略对某个键设置
reserved/limit,该键必须先出现在池上——策略键永远是池键的子集。
热身:单池、单策略、只有 GPU
可抢占步骤借用超出 reserved 的容量
故事:团队有"属于"自己的 4 块 GPU,但池是空的。他们申请 6 块 GPU 且允许抢占,可以借用两块空闲 GPU。
池
{ "name": "datacenter-gpus", "capacity": { "gpu": 8 } }策略(编排器team-ml-orch挂接到该池)
{ "pool": "datacenter-gpus", "component": "team-ml-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } }步骤
from zenml import step from zenml.config import ResourceSettings @step( settings={ "resources": ResourceSettings( gpu_count=6, preemptible=True, ) } ) def train() -> None: ...结果:立即分配(不排队)。4 块 GPU 计入策略的 reserved 份额,2 块是从空闲池容量中借用的(处于 reserved 与 limit 之间,且池仍有空闲单元)。
非抢占步骤保持在 reserved 之内
故事:同样的池与策略。生产任务要 2 块 GPU 并选择不抢占。2 在 4 的预留额度之内。
池
{ "name": "datacenter-gpus", "capacity": { "gpu": 8 } }策略
{ "pool": "datacenter-gpus", "component": "team-ml-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=2, preemptible=False, ) } ) def production_train() -> None: ...结果:分配成功(假设没有其他竞争)。非抢占任务要求每个键满足"请求 ≤ reserved",2 ≤ 4通过。
非抢占步骤超出 reserved
故事:同样的池与策略。生产任务要 6 块 GPU 但拒绝抢占。非抢占工作不能使用 reserved 上方的"借用"区间。
池
{ "name": "datacenter-gpus", "capacity": { "gpu": 8 } }策略
{ "pool": "datacenter-gpus", "component": "team-ml-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=6, preemptible=False, ) } ) def too_large_production_train() -> None: ...结果:立即拒绝(动态运行快速失败)。gpu的 6 超出 reserved(4);非抢占请求不能借用至 limit。这里的教训与对账文档中的结论一致:非抢占任务想要更大的单步请求,必须提高reserved,而不是limit(见 How preemption works)。
CPU、内存与步骤槽位:无界 vs 计量
仅 GPU 的池——CPU 与内存不做配额
故事:你只在池和策略里建模了 GPU。步骤仍会在请求中携带mcpu与memory_mb,但这两个键在池层面被省略时是无界的,本策略也省略了它们——因此它们不会阻塞非抢占工作。
池
{ "name": "training", "capacity": { "gpu": 4 } }策略
{ "pool": "training", "component": "k8s-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 2 }, "limit": { "gpu": 4 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=32, memory="64GiB", preemptible=False, ) } ) def hungry_but_ok_on_gpu() -> None: ...结果:只要没有其他问题就分配。这里只对gpu做门禁;mcpu/memory_mb/step_run在该模式下不受池或策略限制。CPU 和内存保持"仅供参考"状态,直到你为它们添加容量行。
非抢占 CPU 在策略 reserved 之内
故事:你在池上限制毫核 CPU(milli-CPU),再通过策略的 reserved / limit 拆分。非抢占 CPU 需求必须适配每个键的 reserved。
池
{ "name": "training", "capacity": { "gpu": 4, "mcpu": 32000 } }策略
{ "pool": "training", "component": "k8s-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 2, "mcpu": 4000 }, "limit": { "gpu": 4, "mcpu": 32000 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=2, preemptible=False, ) } ) def fits_reserved_cpu() -> None: ...结果:分配成功。cpu_count=2→mcpu2000 ≤ reserved 4000,且gpu合法。
非抢占 CPU 超过策略 reserved
池
{ "name": "training", "capacity": { "gpu": 4, "mcpu": 32000 } }策略
{ "pool": "training", "component": "k8s-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 2, "mcpu": 4000 }, "limit": { "gpu": 4, "mcpu": 32000 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=8, preemptible=False, ) } ) def exceeds_reserved_cpu() -> None: ...结果:拒绝。cpu_count=8→mcpu8000 > reserved 4000;非抢占工作不能在mcpu上向 limit 借用。
带策略mcpu行的可抢占 CPU 突增
池与策略:与《非抢占 CPU 在策略 reserved 之内》相同(池含gpu与mcpu;策略同时设置两个键)。
步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=8, preemptible=True, ) } ) def preemptible_cpu_burst() -> None: ...结果:可以使用mcpu上至 limit 的余量(以及池的空闲容量)进行分配,与 GPU 借用机制类似。
池列出mcpu但策略省略它时——可抢占场景
故事:池限制了总毫核 CPU。策略上没有mcpu时,reserved 默认为 0,limit 回退为池总量。
池
{ "name": "training", "capacity": { "gpu": 4, "mcpu": 8000 } }策略(只含gpu)
{ "pool": "training", "component": "k8s-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 2 }, "limit": { "gpu": 4 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=4, preemptible=True, ) } ) def preemptible_with_pool_mcpu() -> None: ...结果:分配成功,或在可行时排队后分配。mcpu4000 ≤ 有效 limit 8000(池总量)。这印证了核心概念中的回退规则:池定义了键但策略省略该键时,limit 回退到池总量、reserved 默认为 0(见 核心概念)。
池列出mcpu但策略省略它时——非抢占场景
池与策略:与上一示例相同。
步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=1, preemptible=False, ) } ) def non_preemptible_positive_mcpu_zero_reserved() -> None: ...结果:拒绝。任何正的mcpu请求在 reserved 为 0 时对非抢占工作都失败。修复方法:把mcpu加进策略并留足 reserved,或者把mcpu从池中移除(如果你希望池层面 CPU 完全无界的话)。
用step_run限制并发步骤数
故事:你既想要 GPU,又想限制该编排器同时运行的步骤数量。每个步骤恒请求 1 个step_run。
池
{ "name": "training", "capacity": { "gpu": 16, "step_run": 10 } }策略
{ "pool": "training", "component": "k8s-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 8, "step_run": 4 }, "limit": { "gpu": 16, "step_run": 4 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=2, preemptible=True, ) } ) def train() -> None: ...结果:服务端只在gpu与step_run同时有足够空闲单元时才授予分配。如果 GPU 空闲但step_run槽位全被占用,请求会进入队列等待。step_run由服务端为每个步骤自动追加1(这是动态流水线并发放宽的天然抓手)。
pool_resources自定义键
自定义键完整配置
故事:你用pool_resources追踪稀缺的许可证或设备类别(如 TensorRT 会话数)。
池
{ "name": "inference", "capacity": { "gpu": 8, "tensorrt_sessions": 4 } }策略
{ "pool": "inference", "component": "gpu-step-op", "component_type": "step_operator", "priority": 10, "reserved": { "gpu": 2, "tensorrt_sessions": 2 }, "limit": { "gpu": 8, "tensorrt_sessions": 4 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, pool_resources={"tensorrt_sessions": 1}, preemptible=False, ) } ) def infer() -> None: ...结果:当gpu与tensorrt_sessions都满足1 ≤ reserved时分配成功。"无界默认值"不适用于自定义键——池必须列出它们。注意本示例的策略组件类型是step_operator:当步骤使用步骤执行器时,资源请求者就是该步骤执行器而非编排器(见 对账流程)。
自定义键在池上但策略缺失
故事:池容量相同,但策略只定义了gpu。
池
{ "name": "inference", "capacity": { "gpu": 8, "tensorrt_sessions": 2 } }策略
{ "pool": "inference", "component": "gpu-step-op", "component_type": "step_operator", "priority": 10, "reserved": { "gpu": 2 }, "limit": { "gpu": 8 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, pool_resources={"tensorrt_sessions": 1}, preemptible=False, ) } ) def infer() -> None: ...结果:拒绝。策略缺行 →tensorrt_sessions的 reserved 为 0;非抢占任务不能请求正数量。修复方法:把tensorrt_sessions加入策略,或者把步骤标记为可抢占(如果允许借用的话)。
硬性拒绝(不排队)
请求超过池容量
池
{ "name": "small", "capacity": { "gpu": 8 } }策略
{ "pool": "small", "component": "k8s-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 8 }, "limit": { "gpu": 8 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=10, preemptible=True, ) } ) def too_big_for_planet() -> None: ...结果:立即拒绝。10 超出池的gpu总量;请求不会进入队列。这类失败对应ResourceRequestStatus.REJECTED状态(见 src/zenml/enums.py 中的状态枚举)。
请求超过策略 limit(池放得下)
池
{ "name": "shared", "capacity": { "gpu": 8 } }策略
{ "pool": "shared", "component": "team-a-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 2 }, "limit": { "gpu": 4 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=6, preemptible=True, ) } ) def over_team_limit() -> None: ...结果:拒绝。6 超出该组件gpu的 limit(4),即使池里确实有 8 块 GPU。limit 是组件在任何时刻可从池中持有的硬性上限。
争用:队列与优先级
两队同优先级、GPU 不足
故事:Red 与 Blue 编排器共享一个池,策略优先级相同。许多可抢占步骤各要 2 块 GPU,池无法同时满足所有人。
池
{ "name": "shared", "capacity": { "gpu": 8 } }策略
[ { "pool": "shared", "component": "red-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } }, { "pool": "shared", "component": "blue-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } } ]步骤(两队任一方的典型步骤)
@step( settings={ "resources": ResourceSettings( gpu_count=2, preemptible=True, ) } ) def train() -> None: ...结果:请求在池队列中等待,直到 GPU 释放。同一策略优先级下,排序倾向于更早的等待者(FIFO 风格)。当多个请求都在等待时,分配器会优先选择仍能完全落在自己未用 reserved 份额内的请求,而不是必须借用的请求——因此拥有预留余量的团队不会被困在已经超借的另一团队后面,只要下一次授权可以由该预留份额满足。在更高优先级的等待者出现或回收逻辑触发之前,不会发生抢占。
更高优先级胜出;低优先级可能被抢占
故事:Sandbox 用可抢占工作突增。Production 策略优先级更高,当池满时需要 GPU。
池
{ "name": "shared", "capacity": { "gpu": 8 } }策略
[ { "pool": "shared", "component": "sandbox-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } }, { "pool": "shared", "component": "prod-orch", "component_type": "orchestrator", "priority": 100, "reserved": { "gpu": 2 }, "limit": { "gpu": 8 } } ]Sandbox(已持有 6 块 GPU,可抢占)
@step( settings={ "resources": ResourceSettings( gpu_count=6, preemptible=True, ) } ) def sandbox_experiment() -> None: ...Prod(新到达,可抢占,需要 4 块)
@step( settings={ "resources": ResourceSettings( gpu_count=4, preemptible=True, ) } ) def prod_train() -> None: ...结果:如果无法在不回收空间的情况下授予 4 块 GPU,对账器(reconciler)可能会抢占 Sandbox 的可抢占运行(策略优先级更低),让 Prod 继续推进。受害者排序的细节见 How preemption works——其核心规则是:只有preemptible=True的运行会被停止,受害者按策略优先级升序、再按分配时间排序,同时"回收(reclaim)"逻辑允许拥有未用 reserved 份额的等待者把正在借用容量上的可抢占运行挤走。
生产非抢占任务只依赖 reserved 等待
故事:Prod 使用preemptible=False,只申请 reserved 范围内的资源。如果同一栈组件上已有其他非抢占任务占用了预留 GPU,本步骤不会去借用 Sandbox 的突增容量。
池
{ "name": "shared", "capacity": { "gpu": 8 } }策略(与上一示例相同:Sandbox 优先级 10,Prod 优先级 100)
Prod 步骤
@step( settings={ "resources": ResourceSettings( gpu_count=2, preemptible=False, ) } ) def prod_sla_job() -> None: ...结果:如果prod-orch的 reservedgpu(2)已被其他非抢占工作占用,本步骤在队列中等待。它不会拿走 Sandbox 借用的 GPU。出路:提高 Prod 的 reserved、等待其他任务结束,或在策略允许时改用可抢占的 Prod 工作。
多池与多键请求
⚠️关键限制:同一栈组件上的多个策略意味着多个池可能都在尝试满足同一个资源请求,但只有一个池能胜出。请求中的每个键都必须通过该池的检查;ZenML 不会为单个步骤从一个池取
gpu、从另一个池取mcpu。整个请求必须在同一个池与策略上完全满足。
一个编排器绑定两个池——主池胜出
故事:你给同一编排器挂接了指向不同池的两个策略。步骤仍然只产生一个资源请求,会在每个合格池中入队;但最终只有一个池胜出。
池
[ { "name": "eu-west-gpu", "capacity": { "gpu": 16 } }, { "name": "eu-north-gpu", "capacity": { "gpu": 16 } } ]策略
[ { "pool": "eu-west-gpu", "component": "regional-orch", "component_type": "orchestrator", "priority": 20, "reserved": { "gpu": 8 }, "limit": { "gpu": 16 } }, { "pool": "eu-north-gpu", "component": "regional-orch", "component_type": "orchestrator", "priority": 10, "reserved": { "gpu": 8 }, "limit": { "gpu": 16 } } ]步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, preemptible=True, ) } ) def train() -> None: ...结果:服务端先尝试更高策略优先级——先 eu-west 后 eu-north。先授予分配的池拥有本次分配,另一条队列条目作为过期项被丢弃。这适合用作主/备或区域性容量方案,而不是把单步拆到互不相关的配额上。
一个步骤必须在每个池中满足所有键
故事:资格检查是逐池、针对请求上的所有键进行的。如果某个池缺少步骤需要的键,该池视其为零容量——请求在那里不合格。
池 A(仅 GPU)
{ "name": "gpu-only", "capacity": { "gpu": 8 } }池 B(完整组合)
{ "name": "gpu-and-trt", "capacity": { "gpu": 8, "tensorrt_sessions": 4 } }步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, pool_resources={"tensorrt_sessions": 1}, preemptible=True, ) } ) def infer() -> None: ...结果:只含gpu的池无法满足tensorrt_sessions——该维度在那里为零,请求不会在那个池上入队。
教训:把你关心的每个稀缺有界维度都建模在同一个池上(或确保每个候选池对这些键定义相同的键集)。下一节展示mcpu与memory_mb的不同之处:在一个池上省略它们,会让那条路径保持合格,即使另一个池严格计量它们。
双池:高优先级路径计量 CPU/RAM;仅 GPU 路径仍然胜出
故事:一个编排器有两个策略(模式同《一个编排器绑定两个池》)。池 B 的容量与策略包含mcpu和memory_mb,reserved 按小型非抢占任务设计。池 A 只定义gpu,不列出mcpu或memory_mb——因此这些维度在池层面无界,其策略也不为它们预留。一个非抢占步骤申请 1 块 GPU,但 CPU 和内存需求超过池 B 策略允许的范围。高优先级策略(池 B)无法授予该请求;低优先级策略(池 A)可以,因为该路径上请求的 CPU 与内存需求不受配额约束。分配归池 A 所有。
池 A(仅 GPU——池上无mcpu或memory_mb)
{ "name": "gpu-only-fallback", "capacity": { "gpu": 8 } }池 B(GPU 加上计量的 CPU 与内存)
{ "name": "metered-cpu-mem", "capacity": { "gpu": 8, "mcpu": 128000, "memory_mb": 524288 } }策略(同一组件,不同优先级——两者都能授予时优先 B)
[ { "pool": "metered-cpu-mem", "component": "k8s-orch", "component_type": "orchestrator", "priority": 100, "reserved": { "gpu": 4, "mcpu": 4000, "memory_mb": 8192 }, "limit": { "gpu": 8, "mcpu": 64000, "memory_mb": 131072 } }, { "pool": "gpu-only-fallback", "component": "k8s-orch", "component_type": "orchestrator", "priority": 50, "reserved": { "gpu": 4 }, "limit": { "gpu": 8 } } ]步骤
@step( settings={ "resources": ResourceSettings( gpu_count=1, cpu_count=8, memory="32GiB", preemptible=False, ) } ) def train() -> None: ...结果:请求大约映射为mcpu8000 以及32GiB对应的数万memory_mb。对非抢占工作而言,每个键必须 ≤ 你所用路径上策略的 reserved。池 B 的策略只预留mcpu4000 与memory_mb8192,该路径无法满足本步骤。池 A 的策略没有mcpu或memory_mb行;由于这些键在池上缺席,它们不会被当作零容量,因此步骤仅凭gpu就保持合格。对账器从池 A 分配并丢弃池 B 的竞争队列行。如果你希望大型非抢占任务留在计量池上,请提高池 B 的mcpu与memory_mb的 reserved(以及容量),或在ResourceSettings中降低需求——否则仅 GPU 的策略会成为重 CPU/RAM 请求的"逃生通道"。
从源码看状态机与 CLI 速查
上述所有结果最终都落在资源请求的状态上。ResourceRequestStatus枚举定义了完整生命周期:pending(排队)、allocated(已分配)、preempting/preempted(抢占中/已抢占)、cancelled(取消)、rejected(拒绝)、released(释放),见 src/zenml/enums.py。步骤启动器会以退避方式轮询资源请求直到被分配;若请求被拒绝、抢占或取消,客户端会向用户暴露错误(见 对账流程)。
CLI 命令族在 src/zenml/cli/resource_pool.py 中实现,池的容量以 JSON/YAML 字符串解析为整数值:
# 池:创建 / 列出 / 查看 / 更新 / 删除 zenml resource-pool create training-gpus \ --capacity '{"gpu": 8, "step_run": 32}' \ --description "Shared training GPUs for the workspace" zenml resource-pool list zenml resource-pool describe training-gpus zenml resource-pool update training-gpus --capacity '{"gpu": 4}' zenml resource-pool delete training-gpus --yes # 策略:把栈组件挂接到池 zenml resource-pool attach-policy training-gpus my-k8s-orch \ --priority 10 \ --reserved '{"gpu": 2}' \ --limit '{"gpu": 4}' zenml resource-pool attach-policy training-gpus my-remote-operator \ --component-type step_operator \ --priority 5 \ --reserved '{"gpu": 2}' \ --limit '{"gpu": 4}' zenml resource-pool list-policies training-gpus zenml resource-pool list-policies --component my-k8s-orch zenml resource-pool detach-policy training-gpus my-k8s-orch # 请求:查看与清理 zenml resource-request list zenml resource-request describe 01234567-89ab-cdef-0123-456789abcdef zenml resource-request delete 01234567-89ab-cdef-0123-456789abcdef zenml resource-pool requests training-gpus --view queued zenml resource-pool requests training-gpus --view active zenml resource-pool requests training-gpus --view all完整命令族的实现细节(含create/update/attach-policy等各子命令的参数解析与校验)可继续查阅 src/zenml/cli/resource_pool.py;对应的数据模型(池、策略、请求的响应结构)位于 src/zenml/models/v2/core/resource_pool.py、src/zenml/models/v2/core/resource_pool_subject_policy.py 与 src/zenml/models/v2/core/resource_request.py。
参见
- 资源池总览——功能定位与典型使用场景
- 核心概念——池、策略、请求的精确定义
- How preemption works——抢占的受害者排序
- 步骤与流水线配置——
ResourceSettings的完整字段参考(OSS 文档)
【免费下载链接】zenmlZenML 🙏: One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考