外部代码集成入门
了解 Elixir 的一些限制以及克服这些限制的策略。
Elixir的一些限制
到目前为止,我们讨论的都是Elixir和Erlang虚拟机真正发挥优势的场景。几年来迅猛的发展势头,加上Erlang数十年的技术积淀,使我们在需要与成千上万用Erlang或Elixir编写的现有库和包集成时具备了显著优势。
然而,Elixir也存在一些局限性。以下是其中几项:
-
复杂的数学统计库
这类库在性能上可能表现不佳,因为虚拟机并非为数值计算而设计。如果应用依赖于统计计算、数值方法求解或金融运算,虚拟机可能会显得力不从心。
-
基于矩阵的解决方案
在Elixir中朴素地实现矩阵会使用嵌套列表,这并不是表示多维矩阵的有效方式。此外,由于缺乏可变性,修改大型矩阵将非常昂贵,并且无论采用何种数据结构,都会导致大量数据复制。
-
基于共享内存的并行算法
某些算法家族是专为共享内存环境下的并行计算而设计的。例如最小生成树等图算法,在Elixir提供的“无共享”并发模型下难以高效实现。
-
命令行应用程序
在现代硬件上,虚拟机从启动到关闭大约需要0.3秒,因此Elixir在某些脚本语言或能生成原生可执行文件的语言面前并不占优。毕竟,Erlang最初的设计目标是长期运行的系统。此外,每个命令行应用都需要随附虚拟机,除非该应用仅面向Elixir开发者。
-
现有的非Elixir库
你可能会发现需要对接一些已用C或C++等语言实现的原生库。
这并非完整的清单。大多数情况下,接受这些权衡是可以接受的。例如,在可变性、并发性和列表处理方面,Elixir的设计确实会对特定类型的问题带来性能影响。但我们这里讨论的不是这类权衡。
将Elixir与其他语言集成
我们关注的是当Elixir在某个关键问题上存在严重短板时的情况,比如对大规模数据集进行密集统计分析,或处理庞大的机器学习任务。如果Elixir能满足大部分需求,我们无需为了满足应用中最后5%的功能而放弃它。目前已有多种优秀的集成方案可供选择。当Elixir和Erlang虚拟机无法胜任时,我们可以用其他语言和技术解决这些问题,并将其与Elixir代码库无缝整合。
在本章中,我们将展示一些可用于实现这种集成的机制,探讨不同的集成选项,并编写一些基础代码。
三种主要策略
有三种主要方式可以与外部代码集成,每种策略的耦合程度不同。从耦合最紧密的开始:
策略一
应用程序可以共享相同的内存地址空间。可以理解为一个函数在同一个操作系统进程中运行。我们可以将外部代码加载进运行Elixir代码的虚拟机中。这在Erlang虚拟机中通过所谓的原生实现函数(NIFs)来实现。
策略二
代码可以作为同一台机器上的独立程序调用外部代码。可以将其视为另一个操作系统进程,但运行在同一台机器上。在Elixir中,我们通过端口(ports)来实现这一点。
策略三
我们可以借助网络与外部代码通信。这种方式涉及不同的操作系统进程和不同的机器。我们不采用通用方案如HTTP API或消息队列,而是专注于利用Erlang虚拟机特有的技术。我们将通过Erlang分布式协议与外部系统通信。
在本章中,我们将分别探索这些方案的实现方式。我们的目标不是提供完整解决方案,而是快速尝试各种方法,以便深入理解每种方案的权衡取舍。