- 浏览: 580331 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
JamAndVariousAbalone:
存储方式的不同吧。gb_tree是平衡树,list是线性结构。 ...
gb_trees和lists的访问效率相差很大 -
genesislive:
eporf:analyse()写错了,应该改成eprof:an ...
Erlang程序的性能测试工具(1) -
vampirezh:
高手啊 求带 ! 请列出带徒标准
Erlang的未来(2008) -
aiquantong:
great!
rebar工具使用备忘录 (1) -
wccxiaoan:
basho的资源 都没办法打开,不过还是有帮助,谢谢。
关于webmachine
NIF是Erlang OTP R13B03版引入的,在这一版中还只是一个实验特性,按照原计划,NIF在R14B版成为正式特性,相应的API也将在该版之后稳定下来。等不及了,先试试再说。
1. 基本原理
最大的好处是速度。Erlang程序的逻辑当然是用Erlang写的,速度上不能和C比。NIF使我们可以用C实现相同的程序逻辑, 而速度则是C的速度。
简单的说就是将C实现的程序编译成动态共享对象(shared object)后动态加载到Erlang节点中,与Erlang共享内存空间,这与内联驱动(linked driver)有点类似,因此也就同样危险:有缺陷的代码会使整个Erlang节点当掉。
此外,在NIF函数中也不适合做那种太耗时的计算,不然会影响Erlang虚拟机的响应。
2. NIF编程模式
业务逻辑代码一般是在erlang函数中实现,这些函数一般是erlang写的(听上去像废话),作为一门高级的函数语言,Erlang在运行效率上是不能与C比。不过,有了NIF,如果我们对某些erlang函数的效率不满意可以用C的实现替代Erlang实现。
我的理解是:在实现上,某个Erlang模块的某些逻辑功能可以由一个基于NIF的C模块实现,具体来讲就是erlang模块中的某个或某些erlang函数可以对应C模块中一个或多个C函数。这些erlang函数不一定非得export给外界,也可以是模块私有的(但是如果该模块的私有函数没有被其它函数调用则在编译时可能会被编译器优化掉,这种情况下会导致装载NIF库失败)。
这需要告诉Erlang,哪些erlang函数有C版本的NIF实现,在NIF中,每个这样的erlang函数-c函数映射关系由一个C的数据结构(ErlNifFunc)表示,如下:
第一个结构成员name表示对应的要替换掉的erlang函数名,第二个结构成员arity是此erlang函数的参数个数,这两个结构成员就确定了要替换掉的erlang函数;第三个结构成员是进行替换的C实现函数(NIF)。
可以看到,所有进行替换的C函数有着特定、统一的定义格式:
当然,也可以在一个C函数中可以实现多个不同arity大小的erlang函数的业务逻辑。例如根据argc的个数做switch逻辑分支。
最终,通过ERL_NIF_INIT宏将C实现和对应的erlang模块绑定起来,实现NIF的初始化:
MODULE是对应的erlang模块名字,直接用模块名(不要字符串),funcs是NIF中用C实现的相关函数。 load, reload, upgrade, unload是在NIF相关生命周期中调用的C语言的回调函数。
新版本的erlang还提供了一个新的on_load指令(directive)用于在模块装载时自动调用某个函数:
该函数如果调用成功必须返回ok(表示模块正确装载),否则返回其它。一般通过on_load指定的函数在启动时自动调用erlang:load_nif(Path, LoadInfo)装载NIF模块实现。一个例子:
3. hello nif
3.1 一个hello world的例子
erlang模块代码:
NIF实现代码:
3.2 编译
Linux下:
Mac OS下
环境变量ERL_ROOT为erlang-otp的安装路径
4. erlang-c数据交换
如何在两种语言中表示逻辑上相同的数据是写NIF程序关键。对NIF来说,数据的交换分输入和输出两种。
4.1 基本数据的交换
这里涉及的一个主要问题是函数参数的传递和计算结果的返回:即函数调用时将Erlang传来的数据转换成C的,函数计算的结果返回时将C的数据转换成Erlang的。
在erlang中,无论是基本数据类型atom、浮点数、整数,还是复合数据类型tuple, list,都统一被称为term。在NIF的C实现函数中,数据类型ERL_NIF_TERM对应Erlang中的这些term数据。
因此,所有的输入和输出都由统一的ERL_NIF_TERM类型表示,最后所有的NIF的C函数就可以统一用
这样的形式定义了。其中argc表示输入参数的个数,argv数组表示对应的输入参数数据;函数返回值也是ERL_NIF_TERM类型的数据。
4.2 binary数据的交换
erlang和nif实现中最有趣的是binary数据的交换了。这种交换甚至能使erlang变量成为真的“变”量。
NIF实现:
对应的erlang模块:
运行测试:
这段hack代码说明了在Erlang中的binary数据与NIF C中操作的是同一块内存的数据。
这种用法可能什么实际价值,因为无法改变Bin的大小。实际应用中不要这样用,应将ErlNifBinary数据视为只读的。手册说只有enif_alloc_binary或enif_realloc_binary分配的ErlNifBinary才能做修改,一般情况下ErlNifBinary都被nif函数(NIF API)视为只读数据。
4.3 ErlNifEnv环境对象
所有的ERL_NIF_TERM数据都由某个ErlNifEnv管理,后者代表一种环境,一种能持有(英文是host)Erlang term的环境。ERL_NIF_TERM的有效期取决于ErlNifEnv环境的有效期,环境不存在了ERL_NIF_TERM数据也就无效了。
ErlNifEnv环境对象的指针在很多NIF API中做为第一个参数传递进来.
有两种ErlNifEnv环境对象:进程绑定的环境和进程独立的环境。
term数据可以通过enif_make_copy在不同环境间传递拷贝。
1. 基本原理
最大的好处是速度。Erlang程序的逻辑当然是用Erlang写的,速度上不能和C比。NIF使我们可以用C实现相同的程序逻辑, 而速度则是C的速度。
简单的说就是将C实现的程序编译成动态共享对象(shared object)后动态加载到Erlang节点中,与Erlang共享内存空间,这与内联驱动(linked driver)有点类似,因此也就同样危险:有缺陷的代码会使整个Erlang节点当掉。
此外,在NIF函数中也不适合做那种太耗时的计算,不然会影响Erlang虚拟机的响应。
2. NIF编程模式
业务逻辑代码一般是在erlang函数中实现,这些函数一般是erlang写的(听上去像废话),作为一门高级的函数语言,Erlang在运行效率上是不能与C比。不过,有了NIF,如果我们对某些erlang函数的效率不满意可以用C的实现替代Erlang实现。
我的理解是:在实现上,某个Erlang模块的某些逻辑功能可以由一个基于NIF的C模块实现,具体来讲就是erlang模块中的某个或某些erlang函数可以对应C模块中一个或多个C函数。这些erlang函数不一定非得export给外界,也可以是模块私有的(但是如果该模块的私有函数没有被其它函数调用则在编译时可能会被编译器优化掉,这种情况下会导致装载NIF库失败)。
这需要告诉Erlang,哪些erlang函数有C版本的NIF实现,在NIF中,每个这样的erlang函数-c函数映射关系由一个C的数据结构(ErlNifFunc)表示,如下:
typedef struct { const char* name; unsigned arity; ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); } ErlNifFunc;
第一个结构成员name表示对应的要替换掉的erlang函数名,第二个结构成员arity是此erlang函数的参数个数,这两个结构成员就确定了要替换掉的erlang函数;第三个结构成员是进行替换的C实现函数(NIF)。
可以看到,所有进行替换的C函数有着特定、统一的定义格式:
- C函数名字当然可以随便取,不过最好与对应的erlang函数相关;
- C函数第一个参数总是ErlNifEnv,代表着函数调用的上下文环境, 可以通过它得到对应的NIF模块的某些特定数据;
- C函数第二个参数argc对应着Erlang函数的参数个数(erlang中是通过函数参数数量的不同来区分同名函数的);
- C函数的第三个参数argv,按顺序一一对应着erlang函数的参数,参数类型都是统一的ERL_NIF_TERM数据结构的数组。C的数据结构ERL_NIF_TERM对应着erlang中的term,而所有的Erlang数据类型,无论是atom,整型,浮点数,tuple还是list,binary都统一叫term。,数组大小由钱一个参数argc决定,注意数组元素是const的;
- C函数的返回值类型都是ERL_NIF_TERM。
当然,也可以在一个C函数中可以实现多个不同arity大小的erlang函数的业务逻辑。例如根据argc的个数做switch逻辑分支。
最终,通过ERL_NIF_INIT宏将C实现和对应的erlang模块绑定起来,实现NIF的初始化:
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)
MODULE是对应的erlang模块名字,直接用模块名(不要字符串),funcs是NIF中用C实现的相关函数。 load, reload, upgrade, unload是在NIF相关生命周期中调用的C语言的回调函数。
新版本的erlang还提供了一个新的on_load指令(directive)用于在模块装载时自动调用某个函数:
-on_load(FunName/0).
该函数如果调用成功必须返回ok(表示模块正确装载),否则返回其它。一般通过on_load指定的函数在启动时自动调用erlang:load_nif(Path, LoadInfo)装载NIF模块实现。一个例子:
-on_load(init/0). init() -> erlang:load_nif("./hello_nif", 0).
3. hello nif
3.1 一个hello world的例子
erlang模块代码:
-module(hello). -export([say/0, on_load/0]). -on_load(on_load/0). on_load() -> erlang:load_nif("./hello", 0). say() -> "hello, i'm from erlang".
NIF实现代码:
#include "erl_nif.h" static ERL_NIF_TERM say(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return enif_make_string(env, "hello, i'm from C NIF", ERL_NIF_LATIN1); } static ErlNifFunc nif_funcs[] = { {"say", 0, say} }; ERL_NIF_INIT(hello, nif_funcs, NULL, NULL, NULL, NULL);
3.2 编译
Linux下:
gcc -fPIC -shared -o hello.so hello.c -I$ERL_ROOT/usr/include/
Mac OS下
gcc -fPIC -bundle -flat_namespace -undefined suppress -o hello.so hello.c -I$ERL_ROOT/usr/include
环境变量ERL_ROOT为erlang-otp的安装路径
4. erlang-c数据交换
如何在两种语言中表示逻辑上相同的数据是写NIF程序关键。对NIF来说,数据的交换分输入和输出两种。
4.1 基本数据的交换
这里涉及的一个主要问题是函数参数的传递和计算结果的返回:即函数调用时将Erlang传来的数据转换成C的,函数计算的结果返回时将C的数据转换成Erlang的。
在erlang中,无论是基本数据类型atom、浮点数、整数,还是复合数据类型tuple, list,都统一被称为term。在NIF的C实现函数中,数据类型ERL_NIF_TERM对应Erlang中的这些term数据。
因此,所有的输入和输出都由统一的ERL_NIF_TERM类型表示,最后所有的NIF的C函数就可以统一用
ERL_NIF_TERM func(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
这样的形式定义了。其中argc表示输入参数的个数,argv数组表示对应的输入参数数据;函数返回值也是ERL_NIF_TERM类型的数据。
- 对输入参数的处理,例如第一个输入到底是int的还是double的,这取决于程序逻辑的约定。虽然NIF也提供了一系列的enif_is_*函数进行判断,但主要靠程序员自己根据约定转换成C中具体的数据类型。这个转换过程是通过一系列enif_get_*函数完成的。早期版本(R13B)的NIF API还很简陋, 从Erlang term到C的数据转换所支持的基本数据类型只有int, unsigned long和char数组, binary,不过还支持list类型的复合数据。后续版本的NIF开始支持更多数据类型了,例如double;
- 对输出(函数返回)的出来,要将C的数据类型转换成ERL_NIF_TERM,这是通过一系列enif_make_*函数完成的,这组API生产的ERL_NIF_TERM数据最好视为只读的(想想erlang的不变的变量)。从NIF返回给erlang的这些ERL_NIF_TERM数据将由erlang节点管理并负责垃圾回收;
- 所有ERL_NIF_TERM数据的属于某个ErlNifEnv数据,这些ERL_NIF_TERM数据的生命周期都与某个ErlNifEnv数据对象的生命周期有关。
4.2 binary数据的交换
erlang和nif实现中最有趣的是binary数据的交换了。这种交换甚至能使erlang变量成为真的“变”量。
NIF实现:
#include "erl_nif.h" #include <stdio.h> static ERL_NIF_TERM change_bin(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary bin; enif_inspect_binary(env, argv[0], &bin); for (int i=0; i<bin.size; ++i) { ++bin.data[i]; } char buf[256]; sprintf(buf, "change_bin: size=%zu, ptr=%p", bin.size, bin.data); return enif_make_string(env, buf, ERL_NIF_LATIN1); } static ErlNifFunc nif_funcs[] = { {"change_bin", 1, change_bin} }; ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL);
对应的erlang模块:
-module(niftest). -export([change_bin/1]). -on_load(init/0). init() -> erlang:load_nif("./niftest", 0). change_bin(_Bin) -> erlang:error({"NIF not implemented in nif_test at line", ?LINE}).
运行测试:
2> Bin = <<1, 2, 3, 4, 5>>. <<1,2,3,4,5>> 3> niftest:change_bin(Bin). "change_bin: size=5, ptr=0x863548" 4> Bin. <<2,3,4,5,6>> 5> niftest:change_bin(Bin). "change_bin: size=5, ptr=0x863548" 6> Bin. <<3,4,5,6,7>>
这段hack代码说明了在Erlang中的binary数据与NIF C中操作的是同一块内存的数据。
这种用法可能什么实际价值,因为无法改变Bin的大小。实际应用中不要这样用,应将ErlNifBinary数据视为只读的。手册说只有enif_alloc_binary或enif_realloc_binary分配的ErlNifBinary才能做修改,一般情况下ErlNifBinary都被nif函数(NIF API)视为只读数据。
4.3 ErlNifEnv环境对象
所有的ERL_NIF_TERM数据都由某个ErlNifEnv管理,后者代表一种环境,一种能持有(英文是host)Erlang term的环境。ERL_NIF_TERM的有效期取决于ErlNifEnv环境的有效期,环境不存在了ERL_NIF_TERM数据也就无效了。
ErlNifEnv环境对象的指针在很多NIF API中做为第一个参数传递进来.
有两种ErlNifEnv环境对象:进程绑定的环境和进程独立的环境。
- 进程绑定环境:所有NIF实现函数的第一个参数传递的都是此类环境,所有NIF函数调用参数(其它参数)都将属于此环境对象。进程绑定环境对象还提供了相关Erlang调用进程的信息。进程绑定环境对象只在NIF调用时有效,也就是说在不同NIF执行过程中保存并传递进程绑定对象的指针是无意义的(而且很危险);
- 进程独立环境:此类环境对象由API函数enif_alloc_env创建,可用于在不同NIF执行过程中存储term,也可以通过enif_send发送term。进程独立环境对象及其包含的term数据总是有效的,可以通过调用API函数enif_free_env显式的摧毁它。
term数据可以通过enif_make_copy在不同环境间传递拷贝。
发表评论
-
NIF与OS线程
2013-08-31 01:29 1108NIF的OS线程编程模型可以参考The Art of Mult ... -
关于nif
2013-08-19 10:28 5105一、NIF的误用问题 使用NIF是很危险的,一不小心它就会搞 ... -
遇到的riak性能问题
2013-07-23 10:59 24201。 遇到一个奇怪的性能问题,多个进程中用riakc_pb_ ... -
folsom_metrics使用备忘
2013-06-07 15:41 1477folsom是一个通用的统计度量工具。使用很简单,关键是搞清它 ... -
Riak Core与folsom
2012-09-01 11:54 1499folsom是Riak从1.2开始引入。 -
关于Erlang/OTP的application参数配置
2012-08-26 23:27 9133Erlang/OTP中将完成特定功能的一组模块组织起来,称之 ... -
rebar工具使用备忘录 (5)
2012-08-23 18:17 1501haogongju、人人IT网、59n南龙、360doc、as ... -
lager的使用
2012-08-23 15:06 10551haogongju、人人IT网、59n南龙、360doc不要抄 ... -
rebar工具使用备忘录 (4)
2012-08-22 19:20 5618haogongju、人人IT网、59n南龙、360doc、as ... -
rebar工具使用备忘录 (3)
2012-08-22 19:18 1308haogongju、人人IT网、59n南龙、360doc不要抄 ... -
对Riak Core的探索 (9) cheatsheet
2012-08-12 12:58 1679haogongju、人人IT网、59n南龙、360doc不要抄 ... -
对Riak Core的探索 (8)
2012-08-11 18:52 1256haogongju、人人IT网、59n南龙、360doc不要抄 ... -
关于webmachine
2012-08-03 14:38 2821haogongju、人人IT网、59n ... -
使用dialyzer遇到的问题
2012-06-19 18:18 11971. 对自定义behaviour的警告 有洁癖的可能无法忍受这 ... -
关于erlang的iolist
2012-06-17 15:10 2829erlang字符串可以用list结构存放ASCII编码(0~2 ... -
关于erlang的binary
2012-06-02 16:03 73311. binary数据是可以在不 ... -
关于erlang的进程池
2012-05-30 18:42 6132有两种情况需要考虑使 ... -
riak对大数据文件或对象的支持问题
2012-05-24 19:24 1571很遗憾在2011年12月的时 ... -
riak资料汇编
2012-04-10 17:38 2547一、上手 各个操作系统平台上的安装说明:Installati ... -
对riak_core的探索 (5)
2012-04-05 17:31 0Coordinator的使用 一份partition有多个副 ...
相关推荐
基于springboot大学生就业信息管理系统源码数据库文档.zip
基于java的驾校收支管理可视化平台的开题报告
时间序列 原木 间隔5秒钟 20241120
毕业设计&课设_基于 Vue 的电影在线预订与管理系统:后台 Java(SSM)代码,为毕业设计项目.zip
基于springboot课件通中小学教学课件共享平台源码数据库文档.zip
基于java的网上购物商城的开题报告
Delphi人脸检测与识别Demo1fdef-main.zip
基于java的咖啡在线销售系统的开题报告
基于java的自助医疗服务系统的开题报告.docx
内容概要:本文档全面介绍了Visual Basic(VB)编程语言的基础知识和高级应用。首先概述了VB的基本特性和开发环境,随后详细讲述了VB的数据类型、变量、运算符、控制结构、数组、过程与函数、变量作用域等内容。接着介绍了窗体设计、控件使用、菜单与工具栏的设计,文件操作、数据库访问等关键知识点。最后讨论了VB的学习方法、发展历史及其在桌面应用、Web应用、数据库应用、游戏开发和自动化脚本编写等领域的广泛应用前景。 适合人群:初学者和中级程序员,尤其是希望快速掌握Windows桌面应用开发的人群。 使用场景及目标:①掌握VB的基础语法和开发环境;②学会使用VB创建复杂的用户界面和功能完整的应用程序;③理解数据库操作、文件管理和网络编程等高级主题。 其他说明:Visual Basic是一种简单易学且功能强大的编程语言,尤其适合用于开发Windows桌面应用。文中不仅覆盖了基础知识,还包括了大量的实用案例和技术细节,帮助读者快速提升编程技能。
基于java的疫情期间高校防控系统开题报告.docx
基于springboot+vue社区老年人帮扶系统源码数据库文档.zip
基于java的超市商品管理系统的开题报告.docx
基于SpringBoot房屋买卖平台源码数据库文档.zip
xdu限通院23微处理器系统与应用大作业(两只老虎),适应于汇编语言keil软件,
<项目介绍> - 新闻类网站系统,基于SSM(Spring、Spring MVC、MyBatis)+MySQL开发,高分成品毕业设计,附带往届论文 - 不懂运行,下载完可以私聊问,可远程教学 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 --------
基于java的学生网上请假系统的开题报告.docx
社会经济繁荣发展的今天,电子商务得到了飞速发展,网上交易越来越彰显出其独特的优越性,在人们的日常生活中,出现了各种类型的交易网站。其中一个就是车辆易主交易网站,它是一个服务于用户买卖二手车辆的交易网站,为用户提供了平等互利、方便快捷的网上交易平台,通过这一类型的网站,用户可自由出售和购买车辆。 本课题主要根据车辆本身的特性,充分发挥互联网的特点与优势,构建一个以二手车辆为商品、基于互联网平台的车辆易主业务交易管理系统,并根据车辆易主业务交易管理系统的应用需求,进行需求分析,进而对网站系统作规划设计。采用IDEA为运行平台,以SSH为框架,运用HTML语言、JSP技术、MySql数据库、JSP与后台数据库链接等关键技术建设二手车网上交易系统,构建车辆易主交易系统的会员注册与登录,网站首页展示、用户发布商品车辆,用户求购商品车辆,分页浏览、购物系统、用户后台管理、管理员用户后台管理等功能,并使这些功能得以实现并更好为用户服务。网站整体构建完成且测试成功后,用户可以进入网站进行注册、登录,登录后,用户可以在网站上发布自己的闲置车辆或者寻找想要购买的车辆,还可以收藏车辆,管理发布和收藏的车辆,
SQLite3的向量扩展库,windows dll,版本0.1.5
基于C++实现(控制台)商品库存管理系统