演员:如何有效地处理以读取为主的数据

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._ 中找到的访问类型不适合您)。请记住,您现在已经承担了正确锁定的责任,并且要小心谨慎。

【讨论】:

以上是关于演员:如何有效地处理以读取为主的数据的主要内容,如果未能解决你的问题,请参考以下文章

如何分解表以获得最佳查询

如何(有效地)以地图为值插入地图?

有效地读取巨大的 csv 文件?

如何有效地读取和写入太大而无法放入内存的文件?

如何通过读取、递增和更新数据库中的列来有效地保持计数

使用 akka 演员休眠