在Elixir/Erlang中运行C代码:端口还是NIF



我发现Elixir程序可以通过NIF(本机实现的函数)或操作系统级端口运行C代码。在阅读了这些和类似的链接后,我并不完全清楚何时使用其中一种或另一种方法(或者完全使用其他方法?),我觉得对我自己和其他新手来说,有一个直接的比较是很好的。有人能提供吗?

什么是端口

端口基本上是独立的程序,与Erlang虚拟机分开运行。Erlang虚拟机通过标准输入/输出与正在运行的端口通信,生成的端口位于拥有它的Erlang进程后面,可以促进端口与Erlang或Elixir应用程序的其余部分之间的通信。端口是"安全的",因为如果端口崩溃,它不会导致整个Erlang虚拟机瘫痪。

陶瓷可能是对Port模块中已经提供的内容的一种可能的改进和扩展。System.cmd/3还在其底层实现中使用端口。

什么是NIF

本机内联函数或"NIF"是在本质上是共享库/DLL中定义的函数,这些库/DLL由Erlang VM加载,并使用某种公开C兼容ABI的语言编写。NIF比端口更高效(因为它们不必通过STDIN/STDOUT进行通信),在许多方面也更简单(因为你不必处理Elixir和非Elixir代码库之间的数据编码和解码),但它们的安全性也低得多;NIF可能会使Erlang VM崩溃,而长时间运行的NIF可能会锁定Erlang虚拟机(因为调度器无法推断本机代码)。

什么是端口驱动程序

端口驱动程序是将外部代码与Erlang或Elixir代码库集成的一种介于两者之间的方法。与NIF一样,它们被加载到Erlang虚拟机中,因此端口驱动程序可能会使整个虚拟机崩溃或挂起。与端口一样,它们的行为类似于Erlang进程。

我什么时候应该使用端口

  • 您希望您的外部代码表现得像一个普通的Erlang进程(至少足以让这样的进程包装它并代表您的外部码发送/接收消息)
  • 您希望Erlang虚拟机能够在外部代码崩溃中幸存下来
  • 您希望在外部代码中实现长时间运行的任务
  • 您想用不支持C兼容外国金融机构的语言编写外部代码(或者不想处理您语言的外国金融机构设施)

我什么时候应该使用NIF

  • 您希望外部代码的行为类似于普通Erlang函数的集合(特别是如果您希望定义一个导出在本机编译代码中实现的函数的Erlang/Elixir模块)
  • 您希望避免通过标准输入/输出进行通信带来任何潜在的性能打击/开销,和/或避免必须在Erlang术语和外部代码所理解的内容之间进行转换
  • 您有理由相信,您的外部代码正在做的事情既不是长时间运行的,也不可能崩溃(包括,在后一种情况下,如果您正在用类似Rust的东西编写NIF;另请参阅:Rustler),或者
  • 您有理由相信,崩溃或挂起Erlang虚拟机对于您的用例是可以接受的(例如,您的代码是分布式的,并且能够在Erlang节点的突然丢失中幸存下来,或者您正在编写一个桌面应用程序,而应用程序范围的崩溃除了给用户带来不便之外,也没什么大不了的)

何时应该使用端口驱动程序

  • 您希望外部代码的行为像Erlang进程
  • 您希望避免通过标准输入/输出进行通信的开销和/或复杂性
  • 您有理由相信您的端口驱动程序不会崩溃或挂起Erlang虚拟机,或者
  • 您有理由相信Erlang虚拟机的崩溃或挂起不是一个关键问题

你推荐什么

这里有两个方面需要权衡:

  • 类似流程与类似模块
  • 安全与高效

如果你想在类似流程的接口后面获得最大的安全性,请使用端口。

如果你想在类似模块的接口后面获得最大的安全性,那么选择一个具有封装System.cmd/3或直接使用端口与外部代码通信功能的模块

如果你想在类似进程的接口后面提高效率,可以使用端口驱动程序。

如果你想在类似模块的界面后面获得更好的效率,可以使用NIF。

相关内容

  • 没有找到相关文章

最新更新