现在有很多关于不使用锁并使用Erlang之类的Message传递方法的嗡嗡声。或者关于使用函数式编程与C ++ / Java之类的不可变数据结构。
但我关注的是以下内容:
鉴于这一事实,在Erlang等中编写程序是一件痛苦的事情,因为你无法做任何这些事情。可能是,它使程序健壮,但是对于诸如解决线性规划问题或计算凸起等问题,性能更重要,并且当它与并发/事务无关时强制算法的不变性等是一个糟糕的决定。不是吗?
答案 0 :(得分:6)
这就是现实生活:无论语言/平台如何,您都需要考虑这种可能性。在分布式世界(现实世界)中,事情失败了:与之共存。
当然有成本:我们的宇宙中没有任何东西是免费的。但是你不应该使用另一种媒介(例如文件,数据库)而不是在通信管道中穿梭“大对象”吗?您总是可以使用“消息”来指代存储在某处的“大对象”。
当然不是:函数式编程/ Erlang OTP背后的想法是尽可能地“隔离”区域被“共享状态”操纵。此外,明确标记位置共享状态发生变异有助于测试性和可用性。可追溯性。
我相信你错过了重点:没有银弹这样的东西。如果使用Erlang无法成功构建应用程序,则不要这样做。您可以以其他方式始终使用整个系统的其他部分,即使用不同的语言/平台。在这方面,Erlang与其他语言没什么区别:使用合适的工具来做正确的工作。
请记住:Erlang旨在帮助解决并发,异步和分布式问题。它没有针对共享内存块高效工作进行优化,例如......除非你计算与在游戏的共享块上工作的nif
函数的接口: - )
答案 1 :(得分:3)
现实系统总是混合:我不相信现代范式在实践中试图摆脱可变数据和共享状态。
但是,目标不是需要并发访问此共享状态。程序可以分为并发和顺序,并使用消息传递和并发部分的新范例。
并非每个代码都会获得相同的投资:人们担心线程从根本上被“视为有害”。像Apache这样的东西可能需要传统的并发线程,并且像这样的关键技术可能会在几年内仔细改进,因此它可以通过完全并发的共享状态来消除。操作系统内核是另一个例子,“解决问题无论多么昂贵”都可能有意义。
快速但破坏没有任何好处:但是对于新代码,或者没有引起如此多关注的代码,情况可能就是它不是线程 - 安全,它不会处理真正的并发性,因此相对“效率”是无关紧要的。一种方式有效,一种方式无效。
不要忘记可测试性:此外,您可以在测试中放置什么价值?基于线程的共享内存并发性根本无法测试。消息传递并发是。所以现在你遇到的情况是你可以测试一个范例但不能测试另一个范例。那么,知道代码已经过测试的价值是什么?甚至不知道其他代码是否适用于所有情况的危险?
答案 2 :(得分:3)
您的问题中有一些隐含的假设 - 您假设所有数据都适合 在一台机器上,应用程序本质上是本地化的。
如果应用程序太大而无法放在一台机器上,会发生什么?如果应用程序超出一台机器会发生什么?
如果应用程序适合一台计算机,您不希望有一种方法来编写应用程序 一旦它超过一台机器,就会有一种完全不同的编程方式。
如果要创建容错应用程序会发生什么?要做出容错的事情,你需要至少两台物理上分离的机器而不是共享。 当你谈到共享和数据库时,你不会提到像mySQL这样的东西 集群通过维护同步副本来精确地实现容错 物理上分离的机器中的数据 - 有很多消息传递和 复制你在表面上看不到的东西 - Erlang就是暴露了这一点。
您编程的方式不应突然改变以适应容错和可伸缩性。
Erlang主要用于构建容错应用程序。
当您访问共享数据时,多核上的共享数据有其自身的一系列问题 你需要获得一个锁 - 如果你使用全局锁(最简单的方法),你可能会结束 在访问共享数据时停止所有核心。多核上的共享数据访问 由于缓存问题可能会出现问题,如果内核具有本地数据缓存,则访问“远处”数据(在某些其他处理器缓存中)可能非常昂贵。
许多问题本质上是分布式的,数据永远不会在一个地方出现 同时如此 - 这些问题与Erlang的思维方式很吻合。
在分布式设置中,“保证邮件传递”不可能 - 目标计算机可能已崩溃。因此,Erlang无法保证邮件传递 - 它需要一种不同的方法 - 系统会告诉您它是否未能发送消息 (但只有在使用了链接机制时) - 然后您可以编写自己的自定义错误 恢复。)
对于纯数字运算,Erlang不合适 - 但在混合系统中Erlang 擅长管理如何将计算分配给可用的处理器,因此我们看到许多系统中Erlang管理问题的分布和容错方面,但问题本身是用不同的语言解决的。
使用和其他语言
答案 3 :(得分:2)
关于你对Erlang的误解的一些评论:
你的事实不是Erlang的事实。即使您认为Erlang编程很痛苦,您也会发现其他人可以创建一些非常棒的软件。您应该尝试在Erlang中编写IRC服务器,或者其他非常并发的服务器。即使你再也不会使用Erlang,你也会学会以另一种方式思考并发性。但是,当然,你会,因为Erlang非常容易。
那些不了解Erlang的人注定要重新执行它。
好的,原版是关于Lisp的,但是......它是真的!
答案 4 :(得分:1)
例如在数据库中,您必须访问和修改相同的记录
但这是由DB处理的。作为数据库的用户,您只需执行查询,数据库就可以确保它是独立执行的。
至于性能,消除共享状态最重要的一点是它可以实现新的优化。共享状态不是特别有效。你可以让核心在同一个缓存行上进行攻击,并且必须将数据写入内存,否则它可能会保留在寄存器或CPU缓存中。
许多编译器优化依赖于副作用和共享状态的缺失。
你可以说保证这些事情的更严格的语言需要比C更高的优化性能,但它也使编译器实现这些优化变得容易得多。
在单线程代码中出现类似于并发问题的许多问题。现代CPU采用流水线操作,无序执行指令,每个周期可运行3-4个指令。因此,即使在单线程程序中,编译器和CPU能够确定哪些指令可以并行交错和执行也是至关重要的。
答案 5 :(得分:0)
答案 6 :(得分:-1)
为了正确,共享是最佳选择,并尽可能保持数据的标准化。对于即时性,发送消息以通知更改,但始终通过轮询备份它们。消息被丢弃,重复,重新排序,延迟 - 不要依赖它们。
如果速度是你担心的,首先要做单线程和tune the daylights out of it。然后,如果您有多个内核并且知道如何拆分工作,请使用并行性。