Erlang NIF浅析

Erlang NIF简析 Erlang调用C代码时,NIF(Native Implemented Function)是比port driver更简单和有效的实现方式,尤其是编写同步程序中,NIF是非常适合Erlang 的。 1,  基本原理       NIF可以使我们可以用C实现相同的程序逻辑,但速度比用纯Erlang的快,跟C的速度很相近。       C语言编译生成的动态(*.so)在Erlang调用C模块 阅读详情

在Erlang调用C代码时,NIF(Native Implemented Function)是比port driver更简单和有效的实现方式,尤其是编写同步程序中,NIF是非常适合Erlang 的。

1,  基本原理

      NIF可以使我们可以用C实现相同的程序逻辑,但速度比用纯Erlang的快,跟C的速度很相近。

      C语言编译生成的动态库(*.so)在Erlang调用C模块时动态加载到Erlang的进程空间中,所以这是用Erlang调用C代码最高效的方式。调用NIF不用上下文的切换开销,但是安全性不是很高,因为NIF的crash会导致整个Erlang进程crash。

2,  编程模式

      在用NIF编程过程中,业务逻辑的代码一般是用Erlang 编写的,由于虚拟机的原因,Erlang在运行效率上是不如C的,有了NIF之后,对于那些Erlang运行起来比较耗时的模块我们可以用C来实现。

     在用NIF时,我们要告知Erlang哪些函数是用C实现的,在NIF中,每个这样的Erlang-C映射函数由一个C的数据结构ErlNifFunc来表示:

  1. typedef struct  
  2. {  
  3.     const char* name;  
  4.     unsigned arity;  
  5.     ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  
  6. }ErlNifFunc;  

       在上面的类中,name表示要在Erlang中用C替换掉的函数(Erlang中调用的函数名),arity表示name这个函数的参数个数,fptr是一个指向函数的指针,它是name函数对应的C语言实现。

       在C语言中实现的NIF函数要有下面的定义方式:

  1. static ERL_NIF_TERM  FuncName(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])   

      这个函数接受由Erlang传过来的参数,参数列表是argv,参数个数是argc。在该函数中如果要使用传过来的参数,就要用enif_get_*系列函数将argv解析成对应的数据类型,如int, float, tuple, list 等等。

      最终,要通过ERL_NIF_INIT宏将C实现和对应的Erlang模块绑定起来,实现NIF的初始化:

  1. ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)  

       MODULE是对应的erlang模块的名字,直接用模块名,funcs是NIF中用C实现的相关函数映射表,即上面的ErlNifFunc结构,load, reload, upgrade, unload是在NIF相关声明周期中调用的C语言的回调函数。

       在Erlang代码中,要用erlang:load_nif/2来加载NIF到当前进程的内存空间中。

 

3,  数据交换

      这里涉及的一个主要问题是函数参数的传递和计算结果的返回:即函数调用时将Erlang传来的数据转换成C的,函数计算的结果返回时将C的数据转换成Erlang的。

在erlang中,无论是基本数据类型atom、浮点数、整数,还是复合数据类型tuple, list,都统一被称为term。在NIF的C实现函数中,数据类型ERL_NIF_TERM对应Erlang中的这些term数据。

       因此,所有的输入和输出都由统一的ERL_NIF_TERM类型表示,最后所有的NIF的C函数就可以统一用 Erlang代码

  1. ERL_NIF_TERM func(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])          

       这样的形式定义了。其中argc表示输入参数的个数,argv数组表示对应的输入参数数据;函数 返回值也是ERL_NIF_TERM类型的数据。

       对输入参数的处理,例如第一个输入到底是int的还是double的,这取决于程序逻辑的约定。虽然NIF也提供了一系列的enif_is_*函数进行判断,但主要靠程序员自己根据约定转换成C中具体的数据类型。Erlang传给C的参数的转换过程是通过一系列enif_get_*函数完成的。从版本R14A开始,Erlang能支持很多的C语言类型,具体可见官方文档。

      对输出(函数返回)的出来,要将C的数据类型转换成ERL_NIF_TERM,C返回给Erlang的数据的转换过程是通过一系列enif_make_*函数完成的,这组API生产的ERL_NIF_TERM数据最好视为只读的(想想erlang的不变的变量)。从NIF返回给erlang的这些ERL_NIF_TERM数据将由erlang节点管理并负责垃圾回收。

     所有ERL_NIF_TERM数据的属于某个ErlNifEnv数据,这些ERL_NIF_TERM数据的生命周期都与某个ErlNifEnv数据对象的生命周期有关。

4,  简单例子

    我们用NIF实现一个求某个数N以内的素数的程序

cprime.c程序

  1. #include <stdbool.h>  
  2. #include <math.h>  
  3. #include "erl_nif.h"  
  4.   
  5. static bool isPrime(int i)  
  6. {  
  7.         int j;  
  8.         int t = sqrt(i) + 1;  
  9.         for(j = 2; j <= t; ++j)  
  10.         {  
  11.                 if(i % j == 0)  
  12.                         return false;  
  13.         }  
  14.         return true;  
  15. }  
  16.   
  17. static ERL_NIF_TERM findPrime(ErlNifEnv *env, int argc, ERL_NIF_TERM argv[])  
  18. {  
  19.         int n;  
  20.         if(!enif_get_int(env, argv[0], &n))  
  21.                 return enif_make_badarg(env);  
  22.         else  
  23.         {  
  24.                 int i;  
  25.                 ERL_NIF_TERM res = enif_make_list(env, 0);  
  26.                 for(i = 2; i < n; ++i)  
  27.                 {  
  28.                         if(isPrime(i))  
  29.                                 res = enif_make_list_cell(env, enif_make_int(env, i), res);  
  30.                 }  
  31.                 return res;  
  32.         }  
  33. }  
  34.   
  35. static ErlNifFunc nif_funcs[] = {  
  36.         {"findPrime", 1, findPrime}  
  37. };  
  38.   
  39. ERL_NIF_INIT(prime, nif_funcs, NULL, NULL, NULL, NULL)  

   上面的C语言代码中,findPrime的参数由argv传入,argv[0]即是传入的参数N。


erlang代码:

  1. -module(prime).  
  2. -export([load/0, findPrime/1]).  
  3.   
  4. load() ->  
  5.         erlang:load_nif("./cprime", 0).  
  6.   
  7. findPrime(N) ->  
  8.         io:format("this function is not defined!~n").  


make之后运行结果:

  1. 1> prime:load().  
  2. ok  
  3. 2> prime:findPrime(50).  
  4. [47,43,41,37,31,29,23,19,17,13,11,7,5,3]  

如例所示,erlang调用了C语言实现的findPrime函数打印除了50以内的所有素数。

·God never means to let you down, It is yourself.
Windows下使用NIF扩展Erlang方法 Erlang中,NIF(Native Implemented Function)被用来扩展erlang的某些功能,一般用来实现一些erlang很难实现的,或者一些erlang实现效率不高的功能。NIF使用C开发,效率和C接近,比纯erlang实现要高。NIF会编译成动态,直接动态加载到erlang进程空间调用,也是erlang扩展新方法最高效的做法。 阅读详情

相关推荐

Erlang中的NIF(Native Implemented Function)

为了提高Erlang的执行效率,它提供了一种称为NIF(Native Implemented Function)的机制,允许开发者使用C/C++编写原生代码来扩展Erlang的功能。为了提高Erlang的执行效率,它提供了一种称为NIF(Native Implemented Function)的机制,允许开发者使用C/C++编写原生代码来扩展Erlang的功能。NIFErlang的一种扩展机制,允许开发者使用C/C++编写原生代码,并将其作为Erlang函数的一部分进行调用。

AzProcessgroup的博客 292

Windows下使用NIF扩展Erlang完整例子

Windows下使用NIF扩展Erlang完整例子,包含nif工程项目,erlang引用例子。 配套文章:http://blog.csdn.net/mycwq/article/details/17527485

Erlang NIF使用

Erlang NIF使用 NIFErlang源码里经常出现的东西,它像其他函数一样被调用,对调用方来说没区别,本身为C实现,效率较高,今天在Linux下测试一下NIF的自定义实现过程

Nicer_feng's blog 406

erl_nif 扩展erlang的另外一种方法

erl_nif 扩展erlang的另外一种方法

Erlang NIF的使用

Native Implemented Functions(NIF)可以用C来实现程序一些功能的扩展,一般用来实现一些用Erlang无法实现或者实现效率低的功能。 C语言编译生成的动态(*.so)在Erlang调用C模块时动态加载到Erlang的进程空间中,调用NIF不用上下文的切换开销,但是安全性不是很高,因为NIFcrash会导致整个Erlang进程crashNIF的实现 先按官方文档上给的例子,初次实现一下NIF的使用: 1.创建niftest.c文件 #...

YOONGI 1279

erlang -nifs

NIFErlang OTP R13B03版引入的,在这一版中还只是一个实验特性,按照原计划,NIF在R14B版成为正式特性,相应的API也将在该版之后稳定下来。等不及了,先试试再说。 1. 基本原理 最大的好处是速度。Erlang程序的逻辑当然是用Erlang写的,速度上不能和C比。NIF使我们可以用C实现相同的程序逻辑, 而速度则是C的速度。 简单的说就是将C实现的程序编译成动态共享对象

yangzm的专栏 988

erlang nif 中文手册

前言 这是翻译erlang官方文档中的 erts-5.9.2的erl_nif部分。翻译完了。水平有限,我就把这个当作是我自己使用了,以后也会继续完善的。 erlang nif 中文手册 概括 功能 初始化 数据类型 接口-资源分配类 接口-线程操作类 接口-类型操作类 概括 NIF包含了erlang模块

vihbc的专栏 1950

erlang nif test

erlang nif test demo

erl_nif_rustler_过程宏写法

原贴 https://blog.csdn.net/ap114/article/details/118092301 用rust 开发 erlang nif的正确做法

rustler编写erlang nif

https://blog.csdn.net/ap114/article/details/118092301

Erlang中的nif

NIF即是(Native Implemented Function),由c实现的函数。其实即是一些动态比如So、DLL。。。 niferlang的r13b才引进的,是一个比port更简单而且更有效率的方式调用Cnif直接链接到erts proc,不用context switch, 所以是非常有效率的,但是也是最不安全的,nif的异常有可能导致 erts 的崩溃。 废话少说,直接上

jackybay的专栏 1708

ripgrep 跨平台实用指南:3 条命令跑通命令行搜索

在三层嵌套的目录里找一个函数名,靠 IDE 点着找要多久?ripgrep 就是一个为这种场景准备的跨平台命令行搜索工具:它递归遍历目录匹配正则表达式,默认尊重 .gitignore,自动跳过隐藏文件和二进制文件。这篇教程带你从安装到按场景搜索再到配置,全部跑通一遍。 ## 🚀 30 秒上手:一条命令装遍三个系统 安装和第一条搜索命令放在同一节说清。三大系统的包管理器都有现成包,按你所在的系统

gitblog_00388的博客 768

Erlang NIF 示例

会有快捷进入方式,或者全局搜索 VsDevCmd.bat脚本,一般会在·等环境下执行,如果安装正常,一般在。

iclod的专栏 255
上一篇: GDB 结合Core File巧妙分析Crash原因
下一篇: Http协议测试
lxjames833539
博客等级 码龄18年 9粉丝 23原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值