- 浏览: 580325 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
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的误用问题
使用NIF是很危险的,一不小心它就会搞垮你的erlang VM,还会堵塞erlang调度器使VM进入假死状态。
平均每20个使用NIF的项目,就有19个滥用了NIF。参考:NIF Abuse
NIF官方手册其实有所提示:
在例证NIF使用的误区一文中也有提醒使用NIF要小心。
官方手册建议我们得把每个NIF函数调用的时间控制在1ms以内。参考
二、一些基本原理和简单解释:调度器抢占与reductions计数
因为Erlang是软实时系统,其调度器有抢占其它erlang进程的能力。erlang给每个进程分配reductions(默认值是2000),对应普通Erlang函数,每执行一次函数调用会记一次reduction,调度器由此估算进程的执行时间。
参考how Erlang does scheduling
2.1 实验:对erlang进程的reductions计数
通过实验可以验证基本上一个普通erlang函数的调用计为一次reduction。
测试代码如下:
测试使用了bif函数process_info/2,它提供了查询erlang进程Pid当前reductions计数:
process_info(Pid, reductions).
我在一台2007年MacBook和一台台式机上测试,执行一次普通erlang函数调用的时间应该都小于1微秒(10^-6sec):
Erlang R16B01 (erts-5.10.2) [source] [64-bit] [smp:2:2] [async-threads:10] [kernel-poll:false] [systemtap]
Eshell V5.10.2 (abort with ^G)
1> timer:tc(foo, sum, [[]]).
{1,0}
2> timer:tc(foo, sum, [[1,2,3,4,5,6,7]]).
{1,28}
3> timer:tc(foo, sum, [[1,2,3,4,5,6,7]]).
{1,210}
4> timer:tc(foo, sum, [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]]).
{1,210}
5> L = lists:seq(1, 100).
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29|...]
6> timer:tc(foo, sum, [L]).
{2,5050}
9> P = spawn(fun() -> receive Any -> go end, foo:sum(L), receive Any2 -> ok end end).
<0.47.0>
10> process_info(P, reductions).
{reductions,17}
12> P ! go.
go
13> process_info(P, reductions).
{reductions,225}
27> f().
28> L = lists:seq(1, 1000).
29> timer:tc(foo, sum, [L]).
{12,500500}
33> P = spawn(fun() -> receive Any -> go end, foo:sum(L), receive Any2 -> ok end end).
<0.76.0>
34> process_info(P, reductions).
{reductions,17}
35> P ! go.
go
36> process_info(P, reductions).
{reductions,1080}
顺便推算一下
foo:sum([1...1000])大概用掉了1000个reductions,耗时12微秒
估算100个reductions对应1微秒。(不同的处理器上结果差别可能很大,这个是很粗糙的推测,不适合做定量分析。)
一个reduction大致等于一次普通erlang函数调用。实际上由于不同函数执行时间不同,这种计算方法是很粗略的。
以上是对普通erlang函数(翻译成opcode由虚拟机执行的函数)的计算方法,对于IO操作和bif函数调用,reductions的计算又有不同。此外bif又有独特的trap机制保证其宿主进程(即调用进程)能随时被抢占。
2.2 erlang调度原理:通过reductions给进程分配执行时间片
当一个erlang进程被调度执行时会赋给固定数量的reductions,默认是2000,这个进程就一直执行,直到:
BTW:第二种情况下如果消息到达或超时的话该进程将重新进入调度,也就是排到运行队列等待被执行。这也是Actor模型的标准运行模式,详见Beyond Threads And Callbacks - Application Architecture Pros And Cons 之 Actor Model (1 - 1)
在调度器的运行队列中等待的进程由round-robin算法决定执行,该算法给每个erlang进程分配一个固定大小的时间片(time slice),在erlang中就是一定数量的reductions,这些erlang进程都有相同的执行优先度。
参考:Characterizing the Scalability of Erlang VM on Many-core Processors
第3.3.1节
2.3 NIF函数调用与reductions计数
NIF函数调用与普通erlang函数调用有所不同,调用了NIF函数的erlang进程有可能会干扰其它erlang进程的公平调度,这是因为:
1.erlang进程调用NIF函数时要一口气执行完,期间是不会被打断的,也即正在执行NIF函数的erlang进程不能被抢占,不但不能被抢占,而且还堵塞了erlang的调度器进程;
2.一次NIF函数的调用如果只计一个reduction可能不公平,一个NIF函数调用可能要比一个普通的erlang函数调用耗时多了。
对第一点,目前版本的erlang没有什么好办法,我们只能修改程序逻辑以减少NIF函数的工作量,将一次大的计算分解成许多小任务,每个小任务由单独的NIF实现。但是这样做还要考虑第2点。因为即使是分解成小任务的NIF函数可能也是比较耗时的。
可以改写sleepy这个例子来证明一下。首先把休眠10秒的nif拆成10个休眠1秒的nif调用。
任务分解后你可能以为不会再有严重堵塞的情况发生了,但是实际测一下就会发现没什么不同,辛辛苦苦分解了任务好像都做了无用功。
仔细想一下调度所采用的时间片(即2000个reductions)就理解了,对于这种分解,reductions其实只是增加到10倍而已,如果原来一次nif函数调用消耗100个reductions,分解后也只是1000个reductions,远达不到2000。因此调用nif的进程由于没达到2000个reductions而不会被抢占。
另一个角度,通过调整nif函数slumber的执行时间,从1ns到100000ns,测试这些不同耗时的nif函数消耗的reductions,可以发现,尽管nif执行的时间不同,但是其消耗的erlang进程reductions却总是一样。这显然是不太合理的。
2.4 补救办法:让NIF函数“正确”计量进程reductions
这时候,一个NIF API就有了用武之地,enif_consume_timeslice是R16B新增加,它用于帮助NIF函数重新估算reductions。
enif_consume_timeslice函数表示当前调用NIF函数的进程消耗的时间片比例,我理解完整的一个时间片对应着2000 reductions(或者是1ms?)。
该函数的第二个参数是个百分比整数,取值区间在[1,100],例如如果是10,表示消耗了2000*10%=200个reductions。
另外,enif_consume_timeslice重新计算的timeslice是积累的:它计算的是从上次调用到本次调用这段时间内所消耗的timeslice。
其返回值是0/1(布尔值?)。表示当前调用enif_consume_timeslice时,对应的erlang进程所分配的时间片是否已耗完。如果耗完则nif调用应该赶紧退出调用,好让调度器进行抢占并安排其它进程执行。
实验验证:
休眠时间一秒,远超1ms,因此可看成100%
执行修改后的sleepy会发现情况有所改善。
这种在nif实现过程中重新估算reductions的思路,与IO的调度思路是类似的。
三. 另一种解决办法:nif与OS线程
以上都是在NIF中执行耗时计算时,如何尽量避免对Elrang VM不良影响的思路。
另一种解决办法是干脆避免在Erlang进程中掉用NIF直接执行耗时的运算,改成通过OS线程执行这些计算,从而避免Erlang调度器堵塞。
在NIF Abuse一文中作者给出了使用NIF的建议:
大致思路就是将耗时的NIF计算放在一个单独的OS线程中执行,这个线程虽然不能接受Erlang时间发来的消息,但是可以发消息给Erlang进程。这样我们可以在Erlang进程中启动一个OS线程,并等待OS将计算结果以消息的方式发送过来。如前所述,等待消息的Erlang进程会被Erlang调度器抢占,也不会有堵塞调度器的问题。
3.1 例子
enif_thread_create(...
发送消息要注意的是新建一个env
ErlNifEnv *msgenv = enif_alloc_env();
enif_send(NULL, pid, msgenv, msg);
发送完要清除env
enif_clear_env(env);
另外,官方文档中强调,创建的OS线程要join,否则在NIF动态库unload的时候VM会崩溃。
相关讨论.
一个例子
注意:名词erlang进程和OS线程的区别。
四、我的小结
感觉enif_consume_timeslice这个新引入的API还是没能彻底解决进程调度/抢占的问题,而且会带来新问题:
1. 重估NIF原生函数的reduction是个技术细活;
2. NIF原生函数实现中如果调用了第三方库的函数,这种情况就很难重估reductions;
3. 干扰了业务逻辑代码的正常实现逻辑,给开发增加复杂度。
启动OS线程异步计算的解决方案似乎不错,不过却失去了Erlang大并发进程的能力。
也许最终解决方案还是使用Native Process,但是Native Process的支持被一再推迟了,原先(2011)以为R15(2012)就会支持,今年(2013)的最新消息是要到R18才会实现,时间大概是后年(2015)。
参考资料
"Characterizing the Scalability of Erlang VM on Many-core Processors"
时间片(time slice)的名词解释
http://highscalability.com/blog/2013/3/18/beyond-threads-and-callbacks-application-architecture-pros-a.html
使用NIF是很危险的,一不小心它就会搞垮你的erlang VM,还会堵塞erlang调度器使VM进入假死状态。
平均每20个使用NIF的项目,就有19个滥用了NIF。参考:NIF Abuse
NIF官方手册其实有所提示:
引用
Avoid doing lengthy work in NIF calls as that may degrade the responsiveness of the VM. NIFs are called directly by the same scheduler thread that executed the calling Erlang code. The calling scheduler will thus be blocked from doing any other work until the NIF returns
在例证NIF使用的误区一文中也有提醒使用NIF要小心。
官方手册建议我们得把每个NIF函数调用的时间控制在1ms以内。参考
引用
It is hard to give an exact maximum amount of time that a native function is allowed to work, but as a rule of thumb a well behaving native function should return to its caller before a millisecond has passed.
二、一些基本原理和简单解释:调度器抢占与reductions计数
因为Erlang是软实时系统,其调度器有抢占其它erlang进程的能力。erlang给每个进程分配reductions(默认值是2000),对应普通Erlang函数,每执行一次函数调用会记一次reduction,调度器由此估算进程的执行时间。
参考how Erlang does scheduling
引用
Both processes and ports have a "reduction budget" of 2000 reductions. Any operation in the system costs reductions. This includes function calls in loops, calling built-in-functions (BIFs), garbage collecting heaps of that process[n1], storing/reading from ETS, sending messages (The size of the recipients mailbox counts, large mailboxes are more expensive to send to). This is quite pervasive, by the way. The Erlang regular expression library has been modified and instrumented even if it is written in C code. So when you have a long-running regular expression, you will be counted against it and preempted several times while it runs. Ports as well! Doing I/O on a port costs reductions, sending distributed messages has a cost, and so on. Much time has been spent to ensure that any kind of progress in the system has a reduction cost.
引用
This is also why one must beware of long-running NIFs. They do not per default preempt, nor do they bump the reduction counter. So they can introduce latency in your system.
2.1 实验:对erlang进程的reductions计数
通过实验可以验证基本上一个普通erlang函数的调用计为一次reduction。
测试代码如下:
-module(foo). -compile(export_all). sum(L) -> sum(L, 0). sum([], Acc) -> Acc; sum([H|Tail], Acc) -> sum(Tail, H + Acc).
测试使用了bif函数process_info/2,它提供了查询erlang进程Pid当前reductions计数:
process_info(Pid, reductions).
我在一台2007年MacBook和一台台式机上测试,执行一次普通erlang函数调用的时间应该都小于1微秒(10^-6sec):
Erlang R16B01 (erts-5.10.2) [source] [64-bit] [smp:2:2] [async-threads:10] [kernel-poll:false] [systemtap]
Eshell V5.10.2 (abort with ^G)
1> timer:tc(foo, sum, [[]]).
{1,0}
2> timer:tc(foo, sum, [[1,2,3,4,5,6,7]]).
{1,28}
3> timer:tc(foo, sum, [[1,2,3,4,5,6,7]]).
{1,210}
4> timer:tc(foo, sum, [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]]).
{1,210}
5> L = lists:seq(1, 100).
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29|...]
6> timer:tc(foo, sum, [L]).
{2,5050}
9> P = spawn(fun() -> receive Any -> go end, foo:sum(L), receive Any2 -> ok end end).
<0.47.0>
10> process_info(P, reductions).
{reductions,17}
12> P ! go.
go
13> process_info(P, reductions).
{reductions,225}
27> f().
28> L = lists:seq(1, 1000).
29> timer:tc(foo, sum, [L]).
{12,500500}
33> P = spawn(fun() -> receive Any -> go end, foo:sum(L), receive Any2 -> ok end end).
<0.76.0>
34> process_info(P, reductions).
{reductions,17}
35> P ! go.
go
36> process_info(P, reductions).
{reductions,1080}
顺便推算一下
foo:sum([1...1000])大概用掉了1000个reductions,耗时12微秒
估算100个reductions对应1微秒。(不同的处理器上结果差别可能很大,这个是很粗糙的推测,不适合做定量分析。)
一个reduction大致等于一次普通erlang函数调用。实际上由于不同函数执行时间不同,这种计算方法是很粗略的。
以上是对普通erlang函数(翻译成opcode由虚拟机执行的函数)的计算方法,对于IO操作和bif函数调用,reductions的计算又有不同。此外bif又有独特的trap机制保证其宿主进程(即调用进程)能随时被抢占。
2.2 erlang调度原理:通过reductions给进程分配执行时间片
当一个erlang进程被调度执行时会赋给固定数量的reductions,默认是2000,这个进程就一直执行,直到:
- 消耗(consume)掉所有reductions,
- 该进程要等待接受消息而暂停。
BTW:第二种情况下如果消息到达或超时的话该进程将重新进入调度,也就是排到运行队列等待被执行。这也是Actor模型的标准运行模式,详见Beyond Threads And Callbacks - Application Architecture Pros And Cons 之 Actor Model (1 - 1)
在调度器的运行队列中等待的进程由round-robin算法决定执行,该算法给每个erlang进程分配一个固定大小的时间片(time slice),在erlang中就是一定数量的reductions,这些erlang进程都有相同的执行优先度。
参考:Characterizing the Scalability of Erlang VM on Many-core Processors
第3.3.1节
2.3 NIF函数调用与reductions计数
NIF函数调用与普通erlang函数调用有所不同,调用了NIF函数的erlang进程有可能会干扰其它erlang进程的公平调度,这是因为:
1.erlang进程调用NIF函数时要一口气执行完,期间是不会被打断的,也即正在执行NIF函数的erlang进程不能被抢占,不但不能被抢占,而且还堵塞了erlang的调度器进程;
2.一次NIF函数的调用如果只计一个reduction可能不公平,一个NIF函数调用可能要比一个普通的erlang函数调用耗时多了。
对第一点,目前版本的erlang没有什么好办法,我们只能修改程序逻辑以减少NIF函数的工作量,将一次大的计算分解成许多小任务,每个小任务由单独的NIF实现。但是这样做还要考虑第2点。因为即使是分解成小任务的NIF函数可能也是比较耗时的。
可以改写sleepy这个例子来证明一下。首先把休眠10秒的nif拆成10个休眠1秒的nif调用。
sleep() -> lists:foreach(fun(_) -> slumber() end, lists:seq(1, 10)). slumber() -> nif_error(?LINE).
static ERL_NIF_TERM nifslumber(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { usleep(1000000); // 1 second = 1,000,000 microsecond return enif_make_atom(env, "ok"); }
任务分解后你可能以为不会再有严重堵塞的情况发生了,但是实际测一下就会发现没什么不同,辛辛苦苦分解了任务好像都做了无用功。
仔细想一下调度所采用的时间片(即2000个reductions)就理解了,对于这种分解,reductions其实只是增加到10倍而已,如果原来一次nif函数调用消耗100个reductions,分解后也只是1000个reductions,远达不到2000。因此调用nif的进程由于没达到2000个reductions而不会被抢占。
另一个角度,通过调整nif函数slumber的执行时间,从1ns到100000ns,测试这些不同耗时的nif函数消耗的reductions,可以发现,尽管nif执行的时间不同,但是其消耗的erlang进程reductions却总是一样。这显然是不太合理的。
2.4 补救办法:让NIF函数“正确”计量进程reductions
这时候,一个NIF API就有了用武之地,enif_consume_timeslice是R16B新增加,它用于帮助NIF函数重新估算reductions。
enif_consume_timeslice函数表示当前调用NIF函数的进程消耗的时间片比例,我理解完整的一个时间片对应着2000 reductions(或者是1ms?)。
该函数的第二个参数是个百分比整数,取值区间在[1,100],例如如果是10,表示消耗了2000*10%=200个reductions。
另外,enif_consume_timeslice重新计算的timeslice是积累的:它计算的是从上次调用到本次调用这段时间内所消耗的timeslice。
其返回值是0/1(布尔值?)。表示当前调用enif_consume_timeslice时,对应的erlang进程所分配的时间片是否已耗完。如果耗完则nif调用应该赶紧退出调用,好让调度器进行抢占并安排其它进程执行。
实验验证:
static ERL_NIF_TERM nifslumber(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { usleep(1000000); // one second int isExhausted = enif_consume_timeslice(env, 100); return enif_make_atom(env, "ok"); }
休眠时间一秒,远超1ms,因此可看成100%
执行修改后的sleepy会发现情况有所改善。
这种在nif实现过程中重新估算reductions的思路,与IO的调度思路是类似的。
http://www.cnblogs.com/me-sa/archive/2013/01/08/2850910.html 写道
“IO也是公平调度的,把IO的处理量换算成reduction,算在宿主进程的时间片里面。”
三. 另一种解决办法:nif与OS线程
以上都是在NIF中执行耗时计算时,如何尽量避免对Elrang VM不良影响的思路。
另一种解决办法是干脆避免在Erlang进程中掉用NIF直接执行耗时的运算,改成通过OS线程执行这些计算,从而避免Erlang调度器堵塞。
在NIF Abuse一文中作者给出了使用NIF的建议:
引用
As a NIF you have to either respond asynchronously through an internal thread, or you have to cooperate and be ready to yield.
大致思路就是将耗时的NIF计算放在一个单独的OS线程中执行,这个线程虽然不能接受Erlang时间发来的消息,但是可以发消息给Erlang进程。这样我们可以在Erlang进程中启动一个OS线程,并等待OS将计算结果以消息的方式发送过来。如前所述,等待消息的Erlang进程会被Erlang调度器抢占,也不会有堵塞调度器的问题。
3.1 例子
enif_thread_create(...
发送消息要注意的是新建一个env
ErlNifEnv *msgenv = enif_alloc_env();
enif_send(NULL, pid, msgenv, msg);
发送完要清除env
enif_clear_env(env);
另外,官方文档中强调,创建的OS线程要join,否则在NIF动态库unload的时候VM会崩溃。
相关讨论.
引用
You do not have to join a created thread before the nif returns. If the
VM is crashing when a thread-creating nif returns then you are probably
doing something wrong.
"driver unloaded" correspond to "NIF library unloaded". That is quite
natural. Bad things will happen if a dynamic library is unloaded (driver
or nif) while existing threads execute code in that library. A NIF
library is only unloaded as the result of a module upgrade where the
old module gets purged OR if you replace a NIF library by making
repeated calls to erlang:load_nif from the same module.
A safe way to make sure that your thread is joined before the library is
unloaded is to create a resource object that acts as a handle to your
thread. The destructor of the resource can then do join.
Resource objects has a protection mechanism that postpone the unloading
of a nif library until the last resource object with a destructor in
that library is garbage collected. Maybe nif-created threads should have
a similar protection mechanism. Have to think about that...
/Sverker, Erlang/OTP
VM is crashing when a thread-creating nif returns then you are probably
doing something wrong.
"driver unloaded" correspond to "NIF library unloaded". That is quite
natural. Bad things will happen if a dynamic library is unloaded (driver
or nif) while existing threads execute code in that library. A NIF
library is only unloaded as the result of a module upgrade where the
old module gets purged OR if you replace a NIF library by making
repeated calls to erlang:load_nif from the same module.
A safe way to make sure that your thread is joined before the library is
unloaded is to create a resource object that acts as a handle to your
thread. The destructor of the resource can then do join.
Resource objects has a protection mechanism that postpone the unloading
of a nif library until the last resource object with a destructor in
that library is garbage collected. Maybe nif-created threads should have
a similar protection mechanism. Have to think about that...
/Sverker, Erlang/OTP
一个例子
注意:名词erlang进程和OS线程的区别。
四、我的小结
感觉enif_consume_timeslice这个新引入的API还是没能彻底解决进程调度/抢占的问题,而且会带来新问题:
1. 重估NIF原生函数的reduction是个技术细活;
2. NIF原生函数实现中如果调用了第三方库的函数,这种情况就很难重估reductions;
3. 干扰了业务逻辑代码的正常实现逻辑,给开发增加复杂度。
启动OS线程异步计算的解决方案似乎不错,不过却失去了Erlang大并发进程的能力。
也许最终解决方案还是使用Native Process,但是Native Process的支持被一再推迟了,原先(2011)以为R15(2012)就会支持,今年(2013)的最新消息是要到R18才会实现,时间大概是后年(2015)。
参考资料
"Characterizing the Scalability of Erlang VM on Many-core Processors"
时间片(time slice)的名词解释
引用
The period of time for which a process is allowed to run uninterrupted in a pre-emptive multitasking operating system. Generally you want your program to use it's entire time slice and not do anything that gives up control of the CPU while you have it.
http://highscalability.com/blog/2013/3/18/beyond-threads-and-callbacks-application-architecture-pros-a.html
发表评论
-
静态链接与动态链接
2014-09-06 03:24 1552基于gmp开发第三方库,后者以动态链接库(静态库?)对方式发布 ... -
在macbook上安装linux
2014-06-12 10:29 22811. 安装最新的rEFInd > 0.8.2 http: ... -
NIF与OS线程
2013-08-31 01:29 1108NIF的OS线程编程模型可以参考The Art of Mult ... -
遇到的riak性能问题
2013-07-23 10:59 24201。 遇到一个奇怪的性能问题,多个进程中用riakc_pb_ ... -
dialyzer使用备忘
2013-07-04 12:36 1638一、构建PLT文件: 新构建 dialyzer --build ... -
手工从源码制作一个riak安装包
2013-06-22 18:47 1659riak的Makefile文件提供了各个平台上的安装包的生成脚 ... -
folsom_metrics使用备忘
2013-06-07 15:41 1477folsom是一个通用的统计度量工具。使用很简单,关键是搞清它 ... -
git 库永久删除大文件
2013-01-08 11:49 4691无意中把一个装有很多大文件数据的文件夹(./my1202260 ... -
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不要抄 ... -
对Riak Core的探索 (7)
2012-08-10 18:15 1353haogongju、人人IT网、59n南龙、360doc不要抄 ... -
对Riak Core的探索 (6) HTTP接口
2012-08-09 16:16 1542haogongju,人人IT网,360do ... -
对Riak Core的探索 (5) 业务逻辑的实现:数据如何处理
2012-08-07 18:18 1654业务逻辑的实现:数据 ... -
对riak_core的探索 (5) webmachine
2012-08-07 17:49 0人人IT网不要抄我的烂博客了,私人备忘用的。
相关推荐
【标题】:“rustler编写erlang nif” 在Erlang生态系统中,Native Implemented Functions (NIFs) 是一种机制,允许开发者用其他语言(如C、C++或Rust)编写性能关键部分的代码,然后在Erlang虚拟机(VM)中调用。...
在"erlang nif test"这个项目中,我们很显然看到这是一个关于测试Erlang NIF功能的演示。 Erlang是一种面向并发、分布式计算的函数式编程语言,它的设计目标是构建高可用、容错性强的系统。NIFs是Erlang与C交互的...
上古卷轴 NIF 格式工具集 内包含: 3D模型减面优化软件 MooTools PolygonCruncher 11.02 Win Maya 2016 Nif Plugin Updated 2 3-65421-2-3汉化版+扩展功能 批量自动测定图片转DDS 烘焙法线贴图
《NIF光学规范——RMS梯度的重要性》 在光学工程领域,特别是涉及到高能激光系统如美国国家点火装置(NIF)时,光学元件的精确度是至关重要的。NIF是一个大型惯性约束聚变实验装置,其性能很大程度上取决于数千个...
在Erlang中,`NIF (Native Implemented Functions)` 是一种机制,允许开发者使用其他语言(如C或Rust)编写高效性能的代码,并在Erlang虚拟机中调用。本篇主要介绍如何利用Rust语言来开发Erlang NIF,并探讨`erl_nif...
标题"erl_nif 扩展erlang的另外一种方法"指出,本文将讨论如何使用erl_nif库来扩展Erlang的功能。erl_nif是Erlang/OTP系统中的一种机制,允许开发者用C语言编写底层代码,然后在Erlang虚拟机(EVM)中直接调用,从而...
USB.NIF文件是Windows操作系统中一个重要的组件,主要用于支持USB(通用串行总线)设备的正常运行。在描述中提到的问题,当USB.NIF文件缺失或损坏时,可能会导致一系列与USB设备相关的故障,比如无法识别USB设备、...
能帮出3Dmax导入或导出nif格式文件
Windows下使用NIF扩展Erlang完整例子,包含nif工程项目,erlang引用例子。 配套文章:http://blog.csdn.net/mycwq/article/details/17527485
plugin for blender Version 2.5.9 (26 Nov 2012)==============================* Import normals if present for the Blender True Normals patch (requested by kormgar).* New import option to disable bone ...
传奇版转重制版mod材质转换工具,提供给有需要的玩家及mod开发者
NIF,这个被世界瞩目、耗资35亿美元以期实现聚变点火的装置,DOE却报告说短期内(1-2年)在NIF上实现点火是不可能的,中期内(5年)也不确定。苦心研究多年的NIF项目就这样付之东流啦?世界上其他正在运行的激光核...
《深入解析nif.xml:揭示nif文件格式的秘密》 在游戏开发领域,nif(NiNode Interchange Format)文件是一种广泛使用的3D模型数据格式,尤其在Bethesda Softworks的游戏如《上古卷轴》系列中。nif.xml文件是nif文件...
5130美化包,白色nif,超喜欢的,舍不得删
排版方案和切割方案.nif
《NIF5002NT3G-VB N沟道SOT223封装MOSFET的应用解析》 NIF5002NT3G-VB是一款高性能的N沟道MOSFET,适用于SOT223封装,特别适合在便携式设备的负载开关等应用场景中使用。这款器件以其低的导通电阻、高耐压和紧凑的...
《NIF5002NT1G-VB-MOSFET产品应用与参数解析》 NIF5002NT1G-VB是一款N沟道金属氧化物半导体场效应晶体管(MOSFET),其设计适用于便携式设备的负载开关等应用场景。这款MOSFET具有低漏电阻、高电流容量以及良好的热...
盗贼文档|入门|例子Rustler 是一个用安全的 Rust 代码编写 Erlang NIF 的库。这意味着应该没有办法让 BEAM (Erlang VM) 崩溃。该库提供了用于生成与 BEAM 交互的样板的工具,处理 Erlang 术语的编码和解码,并在它们...
按位:NIF示例显示Erlang调度程序的问题bitwise模块实现了几个Erlang本机实现函数(NIF),旨在显示NIF对Erlang调度程序线程可能产生的几种不同影响。 该模块提供的功能的几个变体exor/2采用一个二进制和一个字节值...