演员模型pykka②-示例

例子

Pykka 的 Git 存储库中的examples/目录包含一些 Pykka 使用的可运行示例。

基础演员

import pykka

GetMessages = object()


class PlainActor(pykka.ThreadingActor):
    def __init__(self):
        super().__init__()
        self.stored_messages = []

    def on_receive(self, message):
        if message is GetMessages:
            return self.stored_messages
        else:
            self.stored_messages.append(message)


if __name__ == "__main__":
    actor = PlainActor.start()
    actor.tell({"no": "Norway", "se": "Sweden"})
    actor.tell({"a": 3, "b": 4, "c": 5})
    resp = actor.ask("你好", block=False)  # 设置 block 为 false 则返回 future 对象
    print(resp.get())  # future 对象需要调用get方法获取实际数据
    resp = actor.ask(GetMessages)  # 不设置 block 为 false 则返回实际数据
    print(f"返回信息是:{resp}")  # 直接打印实际数据
    actor.stop()  # 停止演员

有代理的演员

import threading
import time

import pykka


class AnActor(pykka.ThreadingActor):
    field = "演员的字段"

    def proc(self):
        log("proc方法")
        time.sleep(2)
        log("proc方法结束")

    def func(self):
        log("func方法")
        time.sleep(10)  # Block a bit to make it realistic
        return "延迟后返回"


def log(msg):
    thread_name = threading.current_thread().name
    print(f"{thread_name} ====> {msg}")


if __name__ == "__main__":
    actor = AnActor.start().proxy()  # 代理演员
    for _ in range(1):
        # Method with side effect
        log("调用演员的proc方法")
        actor.proc()  # 会开一个线程去执行

        # Method with return value
        log("调用fun方法")
        result = actor.func()  # Does not block, returns a future  # 会开一个线程去执行
        log("阻塞等待结果")
        log(f"结果是:{result.get()}")  # Blocks until ready

        # Field reading
        log("读取演员的字段")
        result = actor.field  # Does not block, returns a future
        log("打印字段(阻塞)")
        log(result.get())  # Blocks until ready

        # Field writing
        log("修改演员的字段")
        actor.field = "new value"  # Assignment does not block
        result = actor.field  # Does not block, returns a future
        log("阻塞打印演员字段")
        log(result.get())  # Blocks until ready
    actor.stop()

多个演员协助

# encoding=utf-8
import pykka


class Adder(pykka.ThreadingActor):
    def add_one(self, i):
        print(f"Adder类-在递增: {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"Bookkeeper类获取: {i} ")


if __name__ == "__main__":
    adder = Adder.start().proxy()
    bookkeeper = Bookkeeper.start(adder).proxy()
    bookkeeper.count_to(10).get()
    pykka.ActorRegistry.stop_all()  # 停止所有的演员
    # 如果Block参数是True,则所有的演员都会被确保停止,停止基于开始的顺序是反向,即后开始的先停止,
    # 这非常有用,如果你有简单的依赖关系在演员之间

共享工作的演员池

# encoding=utf-8
"""
Resolve a bunch of IP addresses using a pool of resolver actors.
使用一个resolver演员池解决一堆IP地址
Based on example contributed by Kristian Klette <klette@klette.us>.

Either run without arguments:

    ./resolver.py

Or specify pool size and IPs to resolve:

    ./resolver.py 3 193.35.52.{1,2,3,4,5,6,7,8,9}
"""

import pprint
import socket
import sys

import pykka


class Resolver(pykka.ThreadingActor):
    def resolve(self, ip):
        try:
            info = socket.gethostbyaddr(ip)
            print(type(info))
            print(info)
            print(f"Finished resolving {ip}")
            return info[0]
        except Exception:
            print(f"Failed resolving {ip}")
            return None


def run(pool_size, *ips):
    # Start resolvers
    # 开启演员池
    resolvers = [Resolver.start().proxy() for _ in range(pool_size)]

    # Distribute work by mapping IPs to resolvers (not blocking)
    # 通过 map 分发IP给代理池(不阻塞)
    hosts = []
    for i, ip in enumerate(ips):
        index = i % len(resolvers)  # 根据余数分配IP给演员
        host = resolvers[index].resolve(ip)  # 代理获取 resolve 方法
        hosts.append(host)

    # Gather results (blocking) 阻塞获取结果
    ip_to_host = zip(ips, pykka.get_all(hosts))  # 获取所有的结果
    pprint.pprint(list(ip_to_host))

    # Clean up
    pykka.ActorRegistry.stop_all()  # 停止所有的演员
    # 如果Block参数是True,则所有的演员都会被确保停止,停止基于开始的顺序是反向,即后开始的先停止,
    # 这非常有用,如果你有简单的依赖关系在演员之间


if __name__ == "__main__":
    if len(sys.argv[1:]) >= 2:
        run(int(sys.argv[1]), *sys.argv[2:])
    else:
        ips = [f"193.35.52.{i}" for i in range(1, 50)]
        run(10, *ips)
posted @ 2022-02-14 19:08  南风丶轻语  阅读(134)  评论(0编辑  收藏  举报