Ray的远程函数功能remote应该被认为是功能性和无副作用的。仅限于远程函数限制我们使用分布式函数式编程,这对于许多用例来说都很好,但实际上有点受限。 Ray使用Actor扩展了数据流模型。Actor本质上是一个有状态的worker(或服务)
假设我们有多个任务在同一个actor上调用方法。例如,我们可能有一个Actor记录来自许多任务的执行信息。我们可以将actor句柄作为参数传递给相关任务来实现这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @ray.remote class Actor (object ): def method (self ): pass actor = Actor.remote() @ray.remote def f (actor ): x_id = actor.method.remote() return ray.get(x_id) f.remote(actor) f.remote(actor) f.remote(actor)
参考官方文档https://docs.ray.io/en/latest/ray-core/patterns/global-variables.html#anti-pattern-using-global-variables-to-share-state-between-tasks-and-actors
全局变量共享是一种反模式的使用方法,不要使用全局变量与任务和参与者共享状态。相反,将全局变量封装在参与者中,并将参与者句柄传递给其他任务和参与者。
Ray 驱动程序、任务和 Actor 运行在不同的进程中,因此它们不共享相同的地址空间。这意味着,如果您在一个进程中修改全局变量,则更改不会反映在其他进程中
解决方案是使用Actor的实例变量来保存全局状态,并将参与者句柄传递到需要修改或访问状态的地方。
成功的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @ray.remote class GlobalVarActor : def __init__ (self ): self .global_var = [] def set_global_var (self, var ): self .global_var.append() def get_global_var (self ): return self .global_var @ray.remote class Actor : def __init__ (self, global_var_actor ): self .global_var_actor = global_var_actor def f (self ): return ray.get(self .global_var_actor.get_global_var.remote()) + 3 global_var_actor = GlobalVarActor.remote() actor = Actor.remote(global_var_actor) ray.get(global_var_actor.set_global_var.remote(4 )) assert ray.get(actor.f.remote()) == 7
失败的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import rayray.init() global_var = 3 @ray.remote class Actor : def f (self ): return global_var + 3 actor = Actor.remote() global_var = 4 assert ray.get(actor.f.remote()) == 6
返回值为6,是因为Actor在定义时 角色方法会运行在一个*有状态(stateful)的工作进程上。实例化一个Actor时,会创建一个全新的worker,并且在该新的Actor上执行所有方法。所以当actor = Actor.remote()时,进程中的global_var值为3,即使后续修改了仍不会生效。
解决办法就是将Actor句柄作为参数传递给相关的任务即可实现全局数据共享。
保证Actor状态的一致性,对同一个Actor的方法调用是串行执行的。多个Actor,是并行地执行Actor的方法的