演员模型pykka⑤-代理
代理
一个演员代理ActorProxy
装饰一个演员引用ActorRef
的实例,这个代理允许参考的演员能被使用,通过规则的方法调用和访问属性。
你可以这么创建代理演员
actor_ref = MyActor.start()
actor_proxy = ActorProxy(actor_ref)
# 或者
actor_proxy = MyActor.start().proxy()
当读取一个属性或者获取一个方法的返回值时,你会获取到一个ThreadingFuture对象,你应该调用get返回获取真正的值
print(actor_proxy.string_attribute.get())
print(actor_proxy.count().get() + 1)
如果你调用一个方法而不关心它的返回值,你就不需要调用get方法,只需要正常调用接口,它就能正常执行
actor_proxy.method_with_side_effect()
如果你想要阻塞,当其他方法在运行的时候,你可以调用get方法,阻塞直到它完成。
actor_proxy.method_with_side_effect().get()
你也可以使用await关键字来等待它
await actor_proxy.method_with_side_effect()
如果你访问一个代理方法作为一个属性,而不调用它,你将获得一个CallableProxy类
代理自己
一个演员可以代理自己,把自己的工作排一个日常表给自己,这个工作表只会在当前信息和所有信息被处理之后工作工作
例如,如果一个演员能分开时间来消费任务,在完成这些任务后,可以通知自己开始下一个任务,使用代理方法或者通过传递信息给他自己,这样能加快处理即将来临的信息,这非常有用,去停止演员,在同一时刻消费多个任务。
创建代理自己的对象,你可以使用actor_ref属性
proxy_to_myself_in_the_future = self.actor_ref.proxy()
如果你创建一个代理自己的对象在构造函数或者on_start方法,你将会创建一个非常好的AP为了你的未来任务
def __init__(self):
...
self._in_future = self.actor_ref.proxy()
...
def do_work(self):
...
self._in_future.do_more_work()
...
def do_more_work(self):
...
为了避免循环引入,你应该使用私有属性,以_开头的命名方式
代理的例子
import pykka
class Adder(pykka.ThreadingActor):
def add_one(self, i):
print(f"{self} is increasing {i}")
return i + 1
class Bookkeeper(pykka.ThreadingActor):
def __init__(self, adder):
super().__init__()
self.adder = adder
def count_to(self, target):
i = 0
while i < target:
i = self.adder.add_one(i).get()
print(f"{self} got {i} back")
if __name__ == "__main__":
adder = Adder.start().proxy()
bookkeeper = Bookkeeper.start(adder).proxy()
bookkeeper.count_to(10).get()
pykka.ActorRegistry.stop_all()
当代理演员访问方法而不调用它时,返回一个CallableProxy
对象实例,可以通过defer方法实现调用
proxy = AnActor.start().proxy()
# Tell semantics are fire and forget. See `defer()` docs.
proxy.do_work.defer()