演员:如何有效地处理以读取为主的数据
Posted
技术标签:
【中文标题】演员:如何有效地处理以读取为主的数据【英文标题】:Actors: How to efficiently handle read-mostly data 【发布时间】:2010-12-04 18:52:51 【问题描述】:假设我有一个只有一个字段的演员。每 100 条发送给参与者的消息中有 99 条读取了该值,第 100 条更新了该值。在这种情况下,我想并行处理读取。换句话说,如何使用 Actors 实现读/写锁的性能?这对于 Scala 标准演员或 Akka 是否实用?还是我错过了演员的重点:)
更新:修复了令人困惑的语言,抱歉
【问题讨论】:
不是所有给演员的消息都是只读的(不可变的)吗?演员收到一条消息并根据消息的内容进行一些处理。如果需要,它会在处理过程中向另一个参与者发送消息。 是的,消息是不可变的。想象一下计数器/增量器作为参与者的常见示例:我想知道读取当前值是否可以非阻塞其他读取操作。 【参考方案1】:[免责声明:我是 Akka 的 PO]
我建议改用代理,读取可以在任何时候完成,但一次只能写入一次。
http://doc.akkasource.org/agents-scala
编辑:http://doc.akka.io/docs/akka/2.1.0/scala/agents.html(试试这个链接)
【讨论】:
+1 代理比尝试在锁上滚动您自己的抽象更简单,并且比 Actor 更适合这个问题。【参考方案2】:你很可能错过了演员的重点。我假设您想要一个向其发送查询的参与者,然后它发回响应。向参与者发送消息、处理消息并返回响应涉及到相当多的机器。响应消息的实际生成将作为任务创建并提交到线程池。在消息队列和线程池之间,有多个地方需要锁或最好的 CAS 操作。通常,关键是演员会根据该消息在单独的线程中完成一些工作。
如果您只想读取数据而很少写入数据(例如递增计数器或访问映射中的值),则最好使用 java.util.concurrent 中的适当类。
【讨论】:
【参考方案3】:我假设您的意思是所有消息都是不可变的,并且几乎所有消息都不会改变参与者的状态。在这种情况下,演员可能不是设计的最佳选择。 Actor 允许您管理任何可变状态,就好像您在处理单线程代码一样。
实际上,每个参与者都有一个邮箱,消息被发送到该邮箱,然后一次处理一个。在您的情况下,这将非常浪费。正如建议的那样,使用 java.util.concurrent 中的某些东西会最有效。
【讨论】:
【参考方案4】:Actor 旨在串行处理消息。这使得它们很容易推理:您一次收到一条消息,因此参与者中的任何变量(只要它们没有被其他任何人改变)都可以在不考虑并发的情况下进行修改。这是最有效的方法吗?绝对不!但是正常工作的效率较低的代码几乎总是比被破坏的高效代码更好。
您所要求的恰恰相反:您想明确考虑并发性(“我知道 99% 的访问将是读取,因此可以并行发生!”)以提高处理速度。在这种情况下,您可能希望使用java.util.concurrent.locks.ReentrantReadWriteLock
直接控制对可变变量的访问(如果在java.util.concurrent.atomic._
中找到的访问类型不适合您)。请记住,您现在已经承担了正确锁定的责任,并且要小心谨慎。
【讨论】:
以上是关于演员:如何有效地处理以读取为主的数据的主要内容,如果未能解决你的问题,请参考以下文章