演员模型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()
posted @ 2022-02-14 19:09  南风丶轻语  阅读(67)  评论(0编辑  收藏  举报