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

Dav*_*man 3 c language-binding compare elixir beam

我发现Elixir程序可以通过NIF(本机实现的功能)OS级别的端口运行C代码.阅读过那些和类似的链接,我不是百分之百地知道何时使用一种或另一种方法(或完全不同的其他方法?),并认为对我自己和其他新手进行直接比较会很好.谁能提供?

Yel*_*ple 10

什么是港口?

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

瓷器可能是一种可能的改进和扩展,而不是Port模块中已经提供的东西. System.cmd/3还在其底层实现中使用端口.

什么是NIF?

本机内联函数或"NIF"是在Erlang VM加载的本质上共享库/ DLL中定义的函数,并使用暴露C兼容ABI的某种语言编写.NIF比端口更有效(因为它们不必通过STDIN/ 进行通信STDOUT)并且在许多方面更简单(因为您不必处理Elixir和非Elixir代码库之间的数据编码和解码),但它们'也不那么安全; NIF 可以使Erlang VM崩溃,并且长时间运行的NIF可能会锁定Erlang VM(因为调度程序无法推断本机代码).

什么是港口司机?

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

我什么时候应该使用端口?

  • 您希望外部代码的行为类似于普通的Erlang进程(至少足以让这样的进程包装它并代表您的外部代码发送/接收消息)
  • 您希望Erlang VM能够在外部代码崩溃后继续存在
  • 您希望在外部代码中实现长时间运行的任务
  • 您希望用不支持C兼容FFI的语言编写外部代码(或者不想处理语言的FFI设施)

我什么时候应该使用NIF?

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

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

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

您有什么推荐的吗?

这里有两个方面的重点:

  • 类似流程的v.模块
  • 安全v.高效

如果您希望在类似流程的界面背后获得最大安全性,请使用端口.

如果您希望在类似模块的接口背后具有最大的安全性,请使用具有包装System.cmd/3或直接使用端口与外部代码通信的功能的模块

如果您希望在类似流程的界面背后获得更高的效率,请使用端口驱动程序.

如果您希望在类似模块的界面背后提高效率,请使用NIF.