c - 在Elixir/Erlang中运行C代码: Ports or NIFs?

标签 c compare elixir beam language-binding

我发现Elixir程序可以通过NIFs (native implemented functions)OS-level ports运行C代码。阅读了这些链接和类似链接后,我不清楚何时使用一种或另一种方法(或完全使用其他方法?),并且对自己和其他新手来说,可以直接进行比较会很好。谁能提供?

最佳答案

什么是端口?

端口基本上是与Erlang VM分开运行的独立程序。 Erlang VM通过标准输入/输出与正在运行的端口进行通信,并且生成的端口位于拥有该端口的Erlang进程的后面,并且可以促进该端口与您的Erlang或Elixir应用程序的其余部分之间的通信。从某种意义上讲,端口是“安全的”,如果端口崩溃,它不会使整个Erlang VM崩溃。

Porcelain作为对Port模块中已经提供的功能的可能改进和扩展,可能会引起人们的兴趣。 System.cmd/3在其基础实现中也使用端口。

什么是NIF?

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

什么是端口驱动程序?

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

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

  • 您希望外部代码的行为类似于普通的Erlang进程(至少足以使该过程将其包装并代表您的外部代码发送/接收消息)
  • 您希望Erlang VM能够在崩溃
  • 的外部代码中生存下来
  • 您想在外部代码
  • 中实现长时间运行的任务
  • 您想用不支持C兼容FFI的语言(或不想使用您语言的FFI工具)编写外部代码。

    什么时候应该使用NIF?
  • 您希望您的外部代码表现得像普通的Erlang函数的集合(特别是如果您想定义一个Erlang/Elixir模块,以导出以 native 编译的代码实现的函数)
  • 您想避免通过标准输入/输出进行通信时可能产生的潜在性能损失/开销,和/或希望避免在Erlang术语与您的外部代码可以理解的内容之间进行转换
  • 您有足够的信心相信您的外部代码所做的事情既不会长时间运行也不会崩溃(包括后一种情况,如果您正在使用Rust之类的代码编写NIF;另请参见:Rustler),或者。 ..
  • 您有理由相信,崩溃或挂起Erlang VM对于您的用例是可接受的(例如,您的代码既是分布式的,又能够在Erlang节点突然丢失的情况下幸免于难,或者您正在编写 table 面应用程序和整个应用程序除了给用户带来不便之外,崩溃并不是什么大问题)

  • 什么时候应该使用端口驱动程序?
  • 您希望外部代码的行为类似于Erlang进程
  • 您要避免通过标准输入/输出
  • 进行通信的开销和/或复杂性
  • 您有足够的信心相信您的端口驱动程序将不会崩溃或挂起Erlang VM,或者...
  • 您有理由相信,Erlang VM的崩溃或挂起不是关键问题

  • 你有什么建议吗?

    这里要权衡两个方面:
  • 类似进程的v。类似模块的
  • 安全v。高效

  • 如果要在类似过程的界面后面获得最大的安全性,请使用端口。

    如果您想在类似模块的界面后面获得最大的安全性,请选择具有包装System.cmd/3或直接使用端口与外部代码进行通信的功能的模块

    如果要在类似进程的界面后面获得更高的效率,请使用端口驱动程序。

    如果要在类似模块的接口(interface)后面获得更高的效率,请使用NIF。

    关于c - 在Elixir/Erlang中运行C代码: Ports or NIFs?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42035912/

    相关文章:

    java - java中栈元素与对象的比较

    python - 寻找一种更优雅(更少代码)的方式来比较多个字典

    r - 将列值与第一行进行比较并保留 R 中的原始值

    elixir - 如何将关联传递给 Ecto 中的变更集?

    postgresql - 使用 Ecto 在 postgres 中生成_series 并将空值检索为 “0”

    chdir() - 没有这样的文件或目录

    c - 我怎样才能在这里将变量传递给函数?

    c - 设置循环次数

    c - "Undefined symbols for architecture x86_64:"在c中是什么意思?

    elixir - ejabberd 打开与 proxy.eu.jabber.org 的 s2s 连接