或换句话说:是否正确使用了可变消息?
我面临的用例是我想要处理基本上类型为
的对象Map<String,List<String>>
演员所做的典型处理是读取或写入地图的某些字段。一个简洁的例子是(省略null
- 测试等。)
map.get("somekey").add("new value");
我的预感是,通过使用相应的集合类型,在Scala中保持这种不可变性是微不足道的。在Java中,它需要一些额外的类库。
但是:阅读Akka文档,我发现sending a message introduces a happens-before relation介于发件人的最后一次访问和接收actor的第一次访问之间。因此,如果map
不是不可变的,那么发件人应该看到所有数据。
假设我可以确保发件人在发送后永远不会再次触摸map
,是否还有其他问题需要关于对此地图的线程数据访问?
答案 0 :(得分:9)
OP对先发条件规则的解释是正确的:“演员发送规则”意味着在向A处理M之前发送M给演员A(这是“相同”所指的)。
回答主要问题:只要最多只有一个演员可以在任何给定的时间点“拥有”可变地图,这将有效,并且根据具体情况,这可能是最有效的解决方案。问题。但是,保证单一所有权将需要一些纪律,这会通过维护成本抵消运行时优势。
虽然最初的问题遗漏了运输Map
的实际载体,但我想强调兰德尔的观点,即演员之间的信息永远不应该是JDK类型,因为那些缺乏语义。在这种情况下,Map
应包含在明确命名的自定义消息类型中。
答案 1 :(得分:1)
如果数据实际上是不可变的,那么你应该没问题。如果数据是不可变的,这将更容易实施,但是通过纪律,您可以在发送后将地图视为有效不可变。
答案 2 :(得分:0)
简而言之,这是避免大量奇怪问题的规则。
潜在的问题是当一个线程修改内存而另一个线程读取该内存时,Java VM有一些奇怪的规则。 Google for&#34; Memory barrier&#34;如果你想知道血淋淋的细节。
这意味着VM上运行的每种语言都会受到影响。
这些规则反过来使得很难判断何时读取某人发送的消息是安全的,因为写入线程可能还没有刷新它的CPU缓存。
解决方案是强制人们使用不可变模式从那时起,当Akka核心接收消息并将其传递给另一个线程时,VM将确保实际刷新缓存。
答案 3 :(得分:0)
Akka docs you reference表示先前发生的规则仅适用于相同的角色。因此,如果您从一个发送者演员向另一个接收者演员发送消息,那么先前发生的规则不适用。
此外,随着您的代码库随着时间的推移而发展,它将变得越来越难以确保&#34;每个修改该Map的唯一演员是原始发件人。
为什么不在原始发件人中创建新的不可变Map,或者在将邮件内容发送给另一个actor之前修改邮件内容的任何其他位置?然后,您将100%确定没有其他参与者可以修改他们收到的消息,并且您可以轻松避免任何并发问题。