Skip to content

API 设计

阅读 Mini Ray 预览版前,先看 API。这里要保留 Ray 的基本语义,而不是只暴露一个线程池。

顶层 API

Mini Ray 暴露这些函数:

python
ray.init(num_workers=4)
ray.shutdown()

ray.remote(fn_or_class)
ray.put(value)
ray.get(ref_or_refs)
ray.wait(refs, num_returns=1, timeout=None)
ray.kill(actor)
ray.metrics()

这组 API 覆盖了 Ray Core 的最小学习面。

remote 同时支持函数和类

函数:

python
@ray.remote
def add(a, b):
    return a + b

ref = add.remote(1, 2)

类:

python
@ray.remote
class Counter:
    ...

counter = Counter.remote()
ref = counter.incr.remote()

因此 remote 需要判断传入对象类型:

python
def remote(obj=None, **options):
    if obj is None:
        return lambda actual: remote(actual, **options)

    if inspect.isclass(obj):
        return RemoteActorClass(obj, options)
    if callable(obj):
        return RemoteFunction(obj, options)
    raise TypeError(...)

为什么不直接返回 Future

Python 标准库已经有 concurrent.futures.Future。Mini Ray 仍然定义 ObjectRef,是为了贴近 Ray 的语义:

  • ObjectRef 表示运行时对象,不只是线程结果。
  • 它可以作为另一个任务的参数。
  • 它可以由 put 创建,也可以由 Task 或 Actor 方法创建。
  • 它把对象存储和任务依赖连接起来。
python
@dataclass(frozen=True)
class ObjectRef:
    object_id: str

这个 ID 是对象系统的核心句柄。

资源选项

Mini Ray 支持:

python
@ray.remote(num_cpus=2)
def cpu_task():
    ...

@ray.remote(num_cpus=1, num_gpus=1)
def gpu_task():
    ...

@ray.remote(resources={"ssd": 1})
def io_task():
    ...

包装对象保留 options:

python
class RemoteFunction:
    def __init__(self, fn, options=None):
        self._fn = fn
        self._options = dict(options or {})

    def options(self, **options):
        merged = dict(self._options)
        merged.update(options)
        return RemoteFunction(self._fn, merged)

这样支持 Ray 常见写法:

python
ref = work.options(num_cpus=2).remote(item)

API 和实现的分界

API 层只负责把用户意图变成运行时请求:

API 层对象运行时请求
RemoteFunction.remote()Runtime.submit_task(...)
RemoteActorClass.remote()Runtime.create_actor(...)
ActorMethod.remote()Runtime.submit_actor_method(...)
ray.get()ObjectStore.get(...)
ray.wait()ObjectStore.wait(...)

这个分界和真实 Ray 的 Python 层 / Core Worker 分界非常像。

小练习

给 Mini Ray 增加一个 ray.is_initialized()

python
def is_initialized():
    return _runtime is not None

再思考:真实 Ray 为什么还要处理地址、命名空间、runtime_env、Job ID 等信息,而 Mini Ray 不需要?

面向学习目的的 Ray Core 中文导读与 Mini Ray 机制预览。