远程调用与消息传递
在 Monarch 中,调用 Actor 的方法不是函数调用,而是一次消息传递。官方把 call、broadcast 这些调用方式称为"副词"(adverb)——它们修饰 endpoint 结果的处理方式。
1. call_one:调用单个 Actor
python
from monarch.actor import Future
# 假设 counter 是上一章在 this_proc() 里启动的单个 Actor
fut: Future[int] = counter.get_value.call_one()
value: int = fut.get()
print(f"Counter value: {value}")- 消息异步发送,立即返回
Future[int],发送者可以继续做别的事; fut.get()阻塞等待结果;在 asyncio 上下文中也可以await;call_one断言你明确知道目标只有一个 Actor。
2. broadcast:广播给整个 Mesh
当你持有的是一组 Actor(ActorMesh)时,一条消息就能发给所有成员:
python
# 通知 8 个 Counter 全部 +1,不等待响应
counters.increment.broadcast()broadcast 是"发射后不管"(fire-and-forget):它不返回可等待的 Future。但所有消息(包括广播)都保证按发送顺序送达。
3. call:广播并收集全部响应
想拿到所有 Actor 的返回值,用 call:
python
# 8 个 Actor 各自返回当前值,聚合成一个列表
results = counters.get_value.call().get()
print(results) # [1, 1, 1, 1, 1, 1, 1, 1]事实上 call_one 就是 call 的特例——当你确定只有一个 Actor 被寻址时使用。
4. 流式响应与随机选择
stream() 让你边到边处理,不必等全部响应凑齐:
python
for future in counters.get_value.stream():
result = future.get()
print(f"Got result: {result}")
process(result)choose() 则从 Mesh 中随机挑一个 Actor 来响应,适合无状态、可互换的服务型 Actor:
python
# 每次调用独立均匀随机选择一个 Actor
result = workers.compute.choose(data).get()⚠️
choose不感知负载,只在大量调用下近似均衡;需要精确控制某个 rank 时,应该切片后用call_one。
5. 消息顺序保证
Monarch 保证 FIFO(先进先出)消息顺序:
- Actor A 先后发给 Actor B 消息 M0、M1,则 B 一定先收到 M0 再收到 M1;
- 发给 mesh 的批量消息,等效于逐个送达每个目标;
- 每个 Actor 串行处理自己的消息:处理完当前消息才会处理下一条;
- 同一进程内不同 Actor 并发处理各自的消息。
python
actor.method1.call_one(arg1) # 消息 M1
actor.method2.call_one(arg2) # 消息 M2
actor.method3.call_one(arg3) # 消息 M3
# Actor 严格按 M1 → M2 → M3 的顺序处理6. 为什么是异步的?
异步设计是高性能分布式的关键:
- 隐藏延迟:网络传输需要时间,异步让 CPU 在等待网络 IO 时继续工作;
- 流水线并行:连续发送多个请求(例如多个 mini-batch),让 GPU 保持忙碌,不必每步停下来同步。
python
futures = []
for i in range(5):
# 连续派发 5 个任务,几乎瞬间完成
futures.append(counters.increment.call())
# 统一收集结果
for i, fut in enumerate(futures):
fut.get()副词速查表
| 副词 | 目标 | 返回 | 典型场景 |
|---|---|---|---|
call_one() | 单个 Actor | Future[Result] | 点对点调用 |
call() | 全部 Actor | Future[List[Result]] | 广播 + 收集响应 |
broadcast() | 全部 Actor | 无(不等响应) | 触发副作用、最高吞吐 |
choose() | 随机一个 | Future[Result] | 无状态服务均衡 |
stream() | 全部 Actor | Iterator[Future] | 响应边到边处理 |
rref() | 全部 Actor | 分布式张量引用 | 张量计算(见中级教程) |
接下来,让我们把视角从单个 Actor 拉远,看看 Monarch 最核心的抽象:Mesh。
