调用spawn_typed<T>(...)后如何访问新创建的类型T实例? (C++ 演员框架)

How can the newly created instance of type T be accessed after calling spawn_typed<T>(...)? (C++ Actor Framework)

在以下示例中,生成的 actor 类型为 a_type,它基于 typed_actor 模板。如何从 a_type 转换为 class A 的实例?

using a_type = typed_actor<replies_to<int>::with<void>>;

class A : public a_type::base
{
protected:
    behavior_type make_behavior() override
    {
        return
        {
            [this](int value)
            {
                aout(this) << value << endl;
            }
        };
    }
};

int main()
{
    a_type spawned = spawn_typed<A>();
}

class A 的一个实例可以通过首先调用 actor_cast 然后使用 dynamic_cast:

来获得
int main()
{
    a_type spawned = spawn_typed<A>();
    abstract_actor* abstractActor = actor_cast<abstract_actor*, a_type>(spawned);
    A* a = dynamic_cast<A*>(abstractActor);
}

Actor 是异步实体,应被视为孤立的。虽然在技术上可以通过 actor_cast 获取原始指针并将其向下转换为实际类型,但我强烈建议不要这样做。在 CAF 中,只允许 actor 本身访问其状态。通过消息传递解耦 actors 避免了竞态条件设计。 Actor 不是直接调用成员,而是将消息发送到其他人的邮箱。这些邮箱是真正的并发主力,并且在没有锁的情况下实现。理想情况下,您生成的 actor 数量多于可用内核数量,因为 actor 应用程序通过将大问题拆分为许多小块来扩展,然后由许多 actor 同时解决。始终牢记阿姆达尔定律:您的应用程序不能比最长的顺序处理链更快。

CAF 中的 actor handles 也启用网络透明。一旦您开始在网络上分发您的应用程序,直接访问状态将根本行不通。此外,如果您使用 state_based actors,从 actor 外部访问状态是 高度不安全的 ,因为一旦 actor 调用 quit() 或被杀了。

基本上可以通过三种方式交换信息:

  • 1:1 消息传递。大多数时候这是正确的解决方案。如果您需要一种特殊的方式与演员沟通,您可以随时使用 scoped_actor
  • N:M 消息使用组传递。这是一种将更新从任意数量的生产者推送到任意数量的订阅者的简单方便的方法。 CAF 提供命名组和 "ad-hoc" 匿名组以允许松散耦合的通信。
  • 共享事务(或同步)数据结构。如果您需要将 actors 集成到现有应用程序中,或者需要将 actors 与其他并发抽象相结合,在 actors 和非 actors 之间共享并发数据结构 can 是一个有效的解决方案。在此模型中,您通过其构造函数将数据结构传递给参与者。但是,在这样做之前,您应该首先考虑使用纯消息传递和组(或参与者池)来组织并发工作人员的设计。这将您的应用程序限制在一台机器上,并取消设计 space 以供将来开发。

Actor 池还支持 1:N 通信(广播)、"scatter/gather" 式工作流等

在任何情况下,破坏 CAF 提供的抽象通常不是一个好主意,您很快就会 "undefined behavior land" 结束。最后一点,如果您发现自己在当前的设计中走投无路,请随时在 CAF 邮件列表上发起讨论。