运行 Elixir/Erlang 中的 C 代码:端口还是 NIF?
Running C code in Elixir/Erlang: Ports or NIFs?
我发现 Elixir 程序可以通过 NIFs (native implemented functions) or via OS-level ports 运行 C 代码。阅读了这些链接和类似链接后,我不是百分百清楚什么时候使用一种或另一种方法(或者完全是其他方法?),并且觉得为我自己和其他新手提供直接比较会很好.谁能提供一下?
什么是端口?
端口基本上是独立于 Erlang VM 运行 的独立程序。 Erlang VM 通过标准 input/output 与 运行ning 端口通信,生成的端口位于拥有它的 Erlang 进程后面,可以促进端口与 Erlang 或 Elixir 应用程序的其余部分之间的通信。端口是 "safe",如果端口崩溃,它不会关闭整个 Erlang VM。
Porcelain 可能会对 Port
模块中已经提供的内容进行改进和扩展。 System.cmd/3
还在其底层实现中使用端口。
什么是 NIF?
本机内联函数或 "NIFs" 是在本质上由 Erlang VM 加载的共享库/DLL 中定义的函数,并使用公开 C-compatible ABI 的某种语言编写。 NIF 比端口更高效(因为它们不必通过 STDIN
/STDOUT
进行通信)并且在许多方面更简单(因为您不必处理编码和解码数据之间的数据) Elixir 和 non-Elixir 代码库),但它们也不太安全; NIF 可以 使 Erlang VM 崩溃,而 long-running NIF 可能会锁定 Erlang VM(因为调度程序无法推理本机代码)。
什么是端口驱动程序?
端口驱动程序是一种 in-between 将外部代码与 Erlang 或 Elixir 代码库集成的方法。与 NIF 一样,它们被加载到 Erlang VM 中,因此端口驱动程序可能会崩溃或挂起整个 VM。与端口一样,它们的行为类似于 Erlang 进程。
什么时候应该使用端口?
- 您希望您的外部代码表现得像一个普通的 Erlang 进程(至少足以让这样的进程代表您的外部代码包装它和 send/receive 消息)
- 您希望 Erlang VM 能够在您的外部代码崩溃后继续存在
- 您想在外部代码中实现 long-running 任务
- 您想使用不支持 C-compatible FFI 的语言编写外部代码(或者不想处理您语言的 FFI 设施)
我什么时候应该使用 NIF?
- 您希望您的外部代码表现得像普通 Erlang 函数的集合(特别是如果您想要定义一个 Erlang/Elixir 模块来导出在 native-compiled 代码中实现的函数)
- 您想避免通过标准通信造成任何潜在的性能影响/开销 input/output and/or 您希望避免在 Erlang 术语和您的外部代码理解的东西之间进行转换
- 您有理由相信您的外部代码正在做的事情既不会 long-running 也不太可能崩溃(包括,在后一种情况下,如果您使用 Rust 之类的语言编写 NIF;另请参阅: Rustler), 或者...
- 您有理由相信崩溃或挂起 Erlang VM 对于您的用例来说是可以接受的(例如,您的代码是分布式的并且能够在 Erlang 节点突然丢失的情况下幸存下来,或者您正在编写桌面应用程序并且application-wide 崩溃除了给用户带来不便之外没什么大不了的)
什么时候应该使用端口驱动程序?
- 您希望您的外部代码表现得像 Erlang 进程
- 您想避免通过标准进行通信的开销 and/or 复杂性 input/output
- 您有理由相信您的端口驱动程序不会崩溃或挂起 Erlang VM,或者...
- 您有理由相信 Erlang VM 的崩溃或挂起不是严重问题
你推荐什么?
这里有两个方面需要权衡:
- Process-like诉module-like
- 安全与高效
如果您想在 process-like 接口后获得最大的安全性,请使用端口。
如果您想在 module-like 接口后获得最大的安全性,请使用具有包装 System.cmd/3
或直接使用端口与外部代码通信的功能的模块
如果你想在 process-like 接口后获得更高的效率,请使用端口驱动程序。
如果你想在 module-like 接口后获得更高的效率,请使用 NIF。
我发现 Elixir 程序可以通过 NIFs (native implemented functions) or via OS-level ports 运行 C 代码。阅读了这些链接和类似链接后,我不是百分百清楚什么时候使用一种或另一种方法(或者完全是其他方法?),并且觉得为我自己和其他新手提供直接比较会很好.谁能提供一下?
什么是端口?
端口基本上是独立于 Erlang VM 运行 的独立程序。 Erlang VM 通过标准 input/output 与 运行ning 端口通信,生成的端口位于拥有它的 Erlang 进程后面,可以促进端口与 Erlang 或 Elixir 应用程序的其余部分之间的通信。端口是 "safe",如果端口崩溃,它不会关闭整个 Erlang VM。
Porcelain 可能会对 Port
模块中已经提供的内容进行改进和扩展。 System.cmd/3
还在其底层实现中使用端口。
什么是 NIF?
本机内联函数或 "NIFs" 是在本质上由 Erlang VM 加载的共享库/DLL 中定义的函数,并使用公开 C-compatible ABI 的某种语言编写。 NIF 比端口更高效(因为它们不必通过 STDIN
/STDOUT
进行通信)并且在许多方面更简单(因为您不必处理编码和解码数据之间的数据) Elixir 和 non-Elixir 代码库),但它们也不太安全; NIF 可以 使 Erlang VM 崩溃,而 long-running NIF 可能会锁定 Erlang VM(因为调度程序无法推理本机代码)。
什么是端口驱动程序?
端口驱动程序是一种 in-between 将外部代码与 Erlang 或 Elixir 代码库集成的方法。与 NIF 一样,它们被加载到 Erlang VM 中,因此端口驱动程序可能会崩溃或挂起整个 VM。与端口一样,它们的行为类似于 Erlang 进程。
什么时候应该使用端口?
- 您希望您的外部代码表现得像一个普通的 Erlang 进程(至少足以让这样的进程代表您的外部代码包装它和 send/receive 消息)
- 您希望 Erlang VM 能够在您的外部代码崩溃后继续存在
- 您想在外部代码中实现 long-running 任务
- 您想使用不支持 C-compatible FFI 的语言编写外部代码(或者不想处理您语言的 FFI 设施)
我什么时候应该使用 NIF?
- 您希望您的外部代码表现得像普通 Erlang 函数的集合(特别是如果您想要定义一个 Erlang/Elixir 模块来导出在 native-compiled 代码中实现的函数)
- 您想避免通过标准通信造成任何潜在的性能影响/开销 input/output and/or 您希望避免在 Erlang 术语和您的外部代码理解的东西之间进行转换
- 您有理由相信您的外部代码正在做的事情既不会 long-running 也不太可能崩溃(包括,在后一种情况下,如果您使用 Rust 之类的语言编写 NIF;另请参阅: Rustler), 或者...
- 您有理由相信崩溃或挂起 Erlang VM 对于您的用例来说是可以接受的(例如,您的代码是分布式的并且能够在 Erlang 节点突然丢失的情况下幸存下来,或者您正在编写桌面应用程序并且application-wide 崩溃除了给用户带来不便之外没什么大不了的)
什么时候应该使用端口驱动程序?
- 您希望您的外部代码表现得像 Erlang 进程
- 您想避免通过标准进行通信的开销 and/or 复杂性 input/output
- 您有理由相信您的端口驱动程序不会崩溃或挂起 Erlang VM,或者...
- 您有理由相信 Erlang VM 的崩溃或挂起不是严重问题
你推荐什么?
这里有两个方面需要权衡:
- Process-like诉module-like
- 安全与高效
如果您想在 process-like 接口后获得最大的安全性,请使用端口。
如果您想在 module-like 接口后获得最大的安全性,请使用具有包装 System.cmd/3
或直接使用端口与外部代码通信的功能的模块
如果你想在 process-like 接口后获得更高的效率,请使用端口驱动程序。
如果你想在 module-like 接口后获得更高的效率,请使用 NIF。