演员模型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)