Protoactor-go是第三方Actor框架,需手动安装;必须通过ActorSystem.Spawn创建Actor并用PID通信,不可直接实例化struct,远程通信需配置remote且两端端口一致。

Proto.Actor 在 Go 里不是标准库,得自己装
Go 没有内置 Actor 模型支持,protoactor-go 是第三方实现,和 Erlang 的 OTP 风格接近但精简很多。不装包就直接 import "github.com/AsynkronIT/protoactor-go" 肯定报错。
实操建议:
- 用
go get github.com/AsynkronIT/protoactor-go@v1.4.0(注意指定 v1.4+,旧版有 panic 风险) - 别混用
protoactor-go和akka-go或go-actor——名字像,API 完全不兼容 - 如果项目用了 Go Modules,确认
go.sum里没残留旧版哈希,否则go build可能静默降级
Actor 启动必须走 ActorSystem,不能 new struct
常见错误是把 Actor 当普通 struct 实例化:myActor := &MyActor{},这样它既没生命周期管理,也不受 mailbox 控制,消息发过去就丢。
正确路径是注册 + spawn:
立即学习“go语言免费学习笔记(深入)”;
- 先调
actor.NewActorSystem()拿到系统实例(全局单例,别重复建) - 用
system.Root.SpawnNamed(props, "my-actor")创建 actor,props由actor.PropsFromProducer构造 -
SpawnNamed返回的是actor.PID,所有通信都靠它,不是 struct 指针 - 别在 actor 内部 spawn 大量子 actor——没做 supervisor 策略的话,panic 会直接 kill 整个 parent
Receive 方法里不能阻塞,也不能 recover panic
Actor 的 Receive 方法是串行执行的,一旦里面调 time.Sleep、等数据库响应、或做同步 HTTP 请求,整个 mailbox 就卡住,后续消息全积压。
更隐蔽的问题是:即使你写了 defer func() { recover() }(),也拦不住 actor 崩溃——protoactor-go 的默认 behavior 是 panic 后自动 stop 该 actor,不会重试也不会 fallback。
- 耗时操作必须用
actor.Context.Ask或异步 goroutine +context.Tell回传结果 - 需要容错?得显式配 supervisor strategy,比如
actor.OneForOneStrategy,并传进Props - 日志打点别用
fmt.Println,用ctx.Log().Info("msg"),否则 log 输出时间戳和 actor ID 全乱
Actor 之间通信只认 PID,跨进程要配 Remote 或 Cluster
本地两个 actor 通信,直接 pid.Tell(ctx, msg) 就行;但想让服务 A 的 actor 发消息给服务 B 的 actor,PID 字符串形如 "127.0.0.1:8080/user/my-actor" 是无效的——没启 remote 功能时,这个地址根本解析不了。
实操关键点:
- 启用远程需额外起
remote.NewRemote并Start,且两端 system 必须用相同remote.Config(尤其注意Host和Port) - PID 序列化依赖
gogoproto,如果消息结构体没加gogoprototag,remote 传过去会解包失败,错误信息是"failed to unmarshal message" - 集群模式(Cluster)比 Remote 更重,要接 Consul/Etcd,别为了简单通信硬上 Cluster
Actor 模型真正难的不是写 Receive,是理清谁该 spawn 谁、谁负责重启、谁持有状态、以及网络分区时消息到底算发没发出去——这些在 protoactor-go 里都得手动补全,没有银弹。










