这个问题描述了演员编程中的演员。什么是消息?如果在消息中发送对象(假设对象存在于 actor 编程中),如何避免共享状态?
1 回答
如果我们认为演员是人,那么消息就像……消息。
假设老板想要对数字列表进行平方根a
,并且不想自己进行所有计算。他可以雇佣一些工人,老板会知道他们的电话号码。
所以老板会给每个工人发短信,告诉他们“求平方根a_i
;完成后回复我555-1234”。该指令是一条消息。然后,Boss 将等待工人完成。
+------+ sqrt(i=0, a_i=9) +------------+
| Boss | ------------------------> | Worker 0 |
+------+ +------------+
| sqrt(i=1, a_i=16) +------------+
‘--------------------------> | Worker 1 |
+------------+
....
Worker 完成计算后,会向 Boss 发送一条短信并报告结果。这也在消息传递中完成。
+------+ set_result(i=0, val=3) +------------+
| Boss | <------------------------ | Worker 0 |
+------+ +------------+
^ set_result(i=1, val=4) +------------+
‘--------------------------- | Worker 1 |
+------------+
....
这听起来像面向对象的编程,但是发送或接收消息时没有顺序 - 它们是异步传递的。(然而,在actor内部,消息是同步接收和排队的。)
当用代码编写时,它可能像
actor Boss:
receive('run'):
worker_addrs = spawn_many(SqrtWorker, len(a)) # hire workers.
for i, addr in enumerate(worker_addrs):
send(addr, 'sqrt', reply_addr=self, i=i, a_i=a[i])
receive('set_value', i, val):
a[i] = val
actor SqrtWorker:
receive('sqrt', reply_addr, i, a_i):
send(reply_addr, 'set_value', i, sqrt(a_i))
quit()
不存在“共享状态问题”,因为不复制就无法共享状态。在我上面的示例中,列表的元素a
被复制到每个工作人员。事实上,只有 Boss 知道存在a
——这是一个地方状态。
现在,如果我们真的想要a
共享怎么办?在actor模型中,我们会将它们转换为一个新的actor,并将这个actor的电话号码发送给Worker。
+------+ sqrt(i=0, a_phoneNum=555-1111) +----------+
| Boss | -------------------------------> | Worker 0 |
+------+ +----------+
+---+
| a |
+---+
然后工人向名单演员询问所需的信息(这是可能的,因为老板已经给a
工人的电话号码。)
+------+ +----------+
| Boss | | Worker 0 |
+------+ +----------+
|
+---+ |
| a | <---------------------------’
+---+ get(i=0)
一段时间后,列表回复...
+------+ +----------+
| Boss | | Worker 0 |
+------+ +----------+
^
+---+ list_val(i=0, val=9) |
| a | ----------------------------’
+---+
那么 Worker 收到消息后就可以计算平方根了list_val
。
+------+ set_result(i=0, val=3) +----------+
| Boss | <------------------------------ | Worker 0 |
+------+ +----------+
+---+
| a |
+---+
Boss终于更新了共享状态
+------+ +----------+
| Boss | | Worker 0 |
+------+ +----------+
| set(i=0, val=3)
| +---+
‘------> | a |
+---+
像这样访问共享状态会有什么问题吗?不——由于接收到的消息a
必须同步运行,所有读/写操作都会相互干扰。因此没有必要弄乱互斥锁。