我们有一个bug是由红宝石工作者(4个进程,每个线程1个)造成的,他们使用遗留的mongodb作为存储进行批处理记录。竞赛条件是围绕着批次是否满;一到三条记录偷偷进入一批。这是通过正确的锁定解决的(尽管它确实减缓了一些事情)。
对于我们的一些服务,我已经讨论过切换到具有并发性的语言,但是如何设计不并发或以不同方式处理并发(例如锁定)的第三方依赖关系。
你能建立一个可爱的并发应用程序,然后通过在其他地方共享状态来毁掉它吗?如果我们使用Erlang/Elixir和Riak,这个问题会避免吗?
发布于 2016-02-12 11:51:26
这是一个非常广泛的问题,您需要意识到,没有一种语言能够自动解决并发问题。可以使用操作系统公开的并发范例编写高度并发的应用程序,或者在像Erlang这样的面向行动者的语言中遇到并发问题。Erlang给您的是更好的抽象和工具,它们使并发问题的推理变得更容易。
以一个简单缓存为例。这样的缓存有数百种不同语言的实现。但是,看看第六章中提出的优秀图书Erlang和OTP在行动中的实现是很有趣的。他们提出了一个体系结构,其中每个密钥都存储在单独的Erlang进程中:
您的简单缓存将存储键/值对,其中键是唯一的,每个键映射到单个值。这个缓存设计的核心思想是,您将使用一个单独的进程来存储您插入的每个值,并将每个键映射到相应的进程。您可能会觉得奇怪,甚至难以置信,您会对每个值使用这样的过程;但是对于像缓存这样的东西,它是有意义的,因为每个值都可能有它自己的生命周期。Erlang对大量轻量级过程的支持使这种方法成为可能。
正确地设计和实现Erlang中的并发应用程序可能需要一些思想上的改变,但一旦您掌握了Erlang与外部世界的接口就很容易了。
Erlang不仅是一种语言,更重要的是,它是一种VM (在某种程度上类似于Java )。它被称为BEAM,它执行编译的Erlang模块。这就是为什么轻量级Erlang进程是可能的--它们是由线程和操作系统进程之上的BEAM提供的抽象。
但是,过程并不是唯一可用的抽象。BEAM公开了TCP和UDP网络套接字,甚至SCTP也可以很容易编程。它允许通过DNS、网络接口或外部进程通过端口查询接口。它还公开了一个在文件上操作的全面的API。这是OTP中可用模块的完整列表,没有提到外部应用程序中可用的模块。
以yexec:sh_cmd/1的实现为例。它执行一个外部命令并使用Erlang端口收集其执行结果(标准输出和错误代码)。它可以并行执行,比如在狼人_P:呼叫/4或bld_lib:呼叫/2中,它们为列表中的每个元素生成一个新的Erlang进程。这可以用于同时启动多个git clone命令,就像bld_deps:do_开始/1所做的那样。
在网络套接字或文件描述符上操作时,同样的原则也适用。Erlang应用程序同时打开几十个套接字或文件描述符并不少见。以里克为例。
如果接口通过端口不够,Erlang支持通过所谓的NIF图书馆直接在主梁VM进程中运行外部C应用程序。本文件概述了与其他语言编写的应用程序的互操作性选项。雅杰勒是一个NIF模块的例子,它允许Erlang进程使用用C语言编写的雅吉库解析JSON。
总之,可以通过OTP和BEAM提供的抽象层编写Erlang中的并发部分并管理外部应用程序。如果在您的应用程序中可能的话,这在很大程度上取决于应用程序的体系结构以及您可以在Erlang中带来和重新实现的共享状态的多少。
https://softwareengineering.stackexchange.com/questions/309890
复制相似问题