python actor_Actor模式——Python实现及应用

本文介绍了Actor模式的概念,提供了一段Python实现Actor模式的代码示例,包括Actor类和PrintActor子类。通过Actor模式,实现了并发计算的解耦,强调单一权责、限制数据成员作用域和线程间独立的并发防御原则。示例展示了如何通过send和receive方法进行消息处理,以及如何设计更复杂的Actor如DatabaseActor和LogActor。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

“并发是一种解耦策略”      —— Robert C.Martin

何为Actor模式呢?

在计算机科学中,参与者模式(Actor model)是一种并发运算上的模型。“参与者”是一种程序上的抽象概念,被视为并发运算的基本单元:当一个参与者接收到一则消息,它可以做出一些决策、创建更多的参与者、发送更多的消息、决定要如何回答接下来的消息。

这段话很全面,但也需要我们花时间来消化与理解。不妨先试着阅读以下这段Python代码实现,再分析理解。

from queue import Queue

from threading import Thread

class ActorExit(Exception):

pass

class Actor(object):

def __init__(self):

self._thread = Thread()

self._queue = Queue()

def send(self, msg):

self._queue.put(msg)

def receive(self):

msg = self._queue.get()

if msg is ActorExit:

raise ActorExit()

return msg

def stop(self):

if self._thread.is_alive():

self.send(ActorExit)

def start(self):

if not self._thread.is_alive():

self._thread = Thread(target=self._bootstrap)

self._thread.start()

def _bootstrap(self):

try:

self.run()

except ActorExit:

pass

def run(self):

while True:

msg = self.receive()

print(msg)

# Sample Actor

class PrintActor(Actor):

def run(self):

while True:

msg = self.receive()

print("Got:", msg)

if __name__ == '__main__':

p = PrintActor()

p.start()

p.send("Hello")

p.send("World")

p.stop()

这里我们定义了Actor模式的基类Actor和其子类实现PrintActor。

Actor对象是一个计算单元,所以每个actor都需要包含了一个Thread对象,用以执行给定的消息处理操作。同时actor对象也包含了一个Queue对象,实现了异步调用(在send消息后能立刻返回控制权)。

在启动actor之后,线程对象会执行引导函数_bootstrap,进而执行run函数。一般来说,在run函数里,我们会通过receive函数来读取之前通过send函数发送来的消息,然后根据给定的逻辑处理消息。特别地,receive函数会抛出ActorExit异常,而ActorExit异常正是我们作为停止线程的哨兵值。

Actor model 作为一种并发运算模型,其作用在于将 目的(做什么)和时机(何时做)解耦,以优化应用程序的吞吐量和结构。例如用户想要打印一段信息,那么他需要去调用对应的PrintActor的send函数(目的),然后程序会立刻返回,继续执行操作;至于这个打印的需求何时(时机)用户则无需关心。而这也是Actor模式吸引人之处——简单性:用户设计时,只需在其子类中定义好 run函数中的处理操作,使用时只需调用send函数,消息就能得到对应的处理。

抽象到一个新的高度,我们可以看到Actor模式在设计上有3个并发防御原则:

单一权责:每个actor只负责处理对应类型的消息,且其中的并发代码和其他组件的代码是分隔开的。

限制数据成员作用域:actor只开放send接口,最大程度地减小内部成员的暴露,限制可能被共享的数据的访问,缩减“临界区”范围。

线程之间独立:每个actor线程都只在自己的世界里存在,不与其他线程共享数据。线程之间唯一的交互是send出去的消息,所以,当消息是不可变对象 或者 actor存储的是消息副本时,就能保证两个线程之间是独立的。

妥善使用Actor模式,保证子类也符合这三个原则,那么程序在架构层面上,能很好地降低多线程应用程序设计的复杂度。

最后,我们发散一下思维。

这里PrintActor是最简单的一种Actor,实践中我们可以设计一个DatabaseActor,用来存储数据;设计一个LogActor,用来记录日志;甚至可以把send方法实现为在socket上的数据传输,将“发送信息”这一概念扩展到多进程甚至是分布式系统之中。

参考书籍:

《Python Cookbook》第三版

《代码整洁之道》Robert C.Martin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值