具有 IPC 和线程的 Actor 系统
Actor system with IPC and Threading
我没听错吗?如果我有一个带有 IPC(进程间通信)和线程的 OS,我可以简单地将它用作 actor 模型。因此,我使用 IPC 发送和接收消息,并将新演员作为线程启动(实际上是进程,因为我不共享内存)。还是我错过了演员模型为满足要求而需要的某些功能?
- 演员需要一个地址:PID
- 向其他参与者发送消息:IPC
- 创建新参与者:进程
这确实是可能的:正如您所说,所有构建基块都在那里。
不过,它似乎不太适合:在 actor 模型中编程时,通常会创建很多 actors,因此 actors 应该是 'cheap'。不幸的是,在大多数操作系统上,进程并不便宜:
- 首先,在典型系统中,PID 的数量是有限的。现在您可以增加
pid_max
以在一定程度上解决这个问题,但这已经表明您可能误用了此工具
- 一个进程可能会有一些状态,因此它需要一些内存页面来存储该状态。即使在进程之间使用智能的写时复制技巧,在一个进程中有许多参与者可能会更多与每个参与者一个进程相比效率更高(除非你开始跨进程共享内存,但你提到你不想这样做,而且实际上似乎很难保证安全)
- 有这么多进程意味着内核调度程序必须对它们进行调度。如果它不会因此而不知所措,我会担心:这将是一个相当不寻常的工作负载,典型的调度程序可能没有针对它进行优化。传统的 actor 系统不会为每个 actor 使用一个线程,而是跟踪消息队列 'internally' 并使用有限数量的线程为所有 actor 提供服务。只要 actor 不阻塞线程,并且您的线程数接近 CPU 的数量,这就会非常有效。
- 故障处理(如果进程崩溃怎么办?)跨进程处理似乎很棘手
所以总而言之,这是可能的,但我不确定这是否是个好主意。不过,看看它在尝试时如何发挥作用会很有趣!
是的,您可以创建简单的 IPC-baced 演员模型,例如 ping-pong。但是,存在一些问题:
你打算如何监督衍生演员? IE。要么你将收到 SIGCHILD
,然后主管(又名 parent-process)将几乎不知道失败的原因,或者从 child-to-supervisor 开发一些更复杂的消息,即描述失败原因。
演员应该相互交流,即会有N-to-N逻辑联系。您打算使用什么 IPC 机制?使用 shared-memory (因为演员编号是动态的并且在运行时配置)或为每对演员使用套接字将非常困难。套接字在系统中也是有限的,它们会很快耗尽(O(N^2),N - actors 的数量)。
演员发现打算怎么做? IE。比如说,你需要一个提供特定服务的特定参与者。 Actor 通过 PID
(system-defined,从程序的角度不可预测)识别。 actor-X 如何能够发现 actor-Y 的 PID
,你知道,应该提供一些 Y-service?您可以 pre-spawn 启动时的所有演员,然后您将知道他们的所有地址 (PIDs
),但是您打算如何按需动态生成新演员并让 already-spawned 演员知道新 PIDs
吗?
在你的系统中,actors 之间的消息传递会产生巨大的开销,因为它将通过内核进行调解(即在进程之间切换),无论你使用哪个 IPC。 sobjectizer 每秒能够传递 700 万条 ping-pong 消息(当它们在同一个线程上时,200 万是 actor 在不同线程上)。
我建议您查看演员模型的现有 C++ 实现,即 sobjectizer、caf 或 rotor因为他们已经解决了所描述的问题(以及许多其他问题)。
我没听错吗?如果我有一个带有 IPC(进程间通信)和线程的 OS,我可以简单地将它用作 actor 模型。因此,我使用 IPC 发送和接收消息,并将新演员作为线程启动(实际上是进程,因为我不共享内存)。还是我错过了演员模型为满足要求而需要的某些功能?
- 演员需要一个地址:PID
- 向其他参与者发送消息:IPC
- 创建新参与者:进程
这确实是可能的:正如您所说,所有构建基块都在那里。
不过,它似乎不太适合:在 actor 模型中编程时,通常会创建很多 actors,因此 actors 应该是 'cheap'。不幸的是,在大多数操作系统上,进程并不便宜:
- 首先,在典型系统中,PID 的数量是有限的。现在您可以增加
pid_max
以在一定程度上解决这个问题,但这已经表明您可能误用了此工具 - 一个进程可能会有一些状态,因此它需要一些内存页面来存储该状态。即使在进程之间使用智能的写时复制技巧,在一个进程中有许多参与者可能会更多与每个参与者一个进程相比效率更高(除非你开始跨进程共享内存,但你提到你不想这样做,而且实际上似乎很难保证安全)
- 有这么多进程意味着内核调度程序必须对它们进行调度。如果它不会因此而不知所措,我会担心:这将是一个相当不寻常的工作负载,典型的调度程序可能没有针对它进行优化。传统的 actor 系统不会为每个 actor 使用一个线程,而是跟踪消息队列 'internally' 并使用有限数量的线程为所有 actor 提供服务。只要 actor 不阻塞线程,并且您的线程数接近 CPU 的数量,这就会非常有效。
- 故障处理(如果进程崩溃怎么办?)跨进程处理似乎很棘手
所以总而言之,这是可能的,但我不确定这是否是个好主意。不过,看看它在尝试时如何发挥作用会很有趣!
是的,您可以创建简单的 IPC-baced 演员模型,例如 ping-pong。但是,存在一些问题:
你打算如何监督衍生演员? IE。要么你将收到
SIGCHILD
,然后主管(又名 parent-process)将几乎不知道失败的原因,或者从 child-to-supervisor 开发一些更复杂的消息,即描述失败原因。演员应该相互交流,即会有N-to-N逻辑联系。您打算使用什么 IPC 机制?使用 shared-memory (因为演员编号是动态的并且在运行时配置)或为每对演员使用套接字将非常困难。套接字在系统中也是有限的,它们会很快耗尽(O(N^2),N - actors 的数量)。
演员发现打算怎么做? IE。比如说,你需要一个提供特定服务的特定参与者。 Actor 通过
PID
(system-defined,从程序的角度不可预测)识别。 actor-X 如何能够发现 actor-Y 的PID
,你知道,应该提供一些 Y-service?您可以 pre-spawn 启动时的所有演员,然后您将知道他们的所有地址 (PIDs
),但是您打算如何按需动态生成新演员并让 already-spawned 演员知道新PIDs
吗?在你的系统中,actors 之间的消息传递会产生巨大的开销,因为它将通过内核进行调解(即在进程之间切换),无论你使用哪个 IPC。 sobjectizer 每秒能够传递 700 万条 ping-pong 消息(当它们在同一个线程上时,200 万是 actor 在不同线程上)。
我建议您查看演员模型的现有 C++ 实现,即 sobjectizer、caf 或 rotor因为他们已经解决了所描述的问题(以及许多其他问题)。