在
素数求解,兼谈Erlang的性能特性一文中比较了Erlang和Java实现的素数求解效率。
在我的MacBook(Intel Core Duo,2GHz,2GB,Leopard 10.5.8)上,计算1000000以内素数:
Java程序的计算时间大概在2850ms左右。
C程序的计算时间在890ms左右。
Erlang程序的计算时间在3900ms左右
采用NIF方式实现的素数查找,计算时间在900ms左右,效率与C程序的相差无几,确实如愿提高了计算效率。
不过个人觉得像文件操作还是使用Port/Driver比较好的,因为对文件的使用可能是一系列持续的操作过程,文件句柄这样的东西还是比较方便的说,NIF比较适合数学函数这样的简单输入->计算->输出
代码如下:
#include <stdbool.h>
#include <math.h>
#include "erl_nif.h"
static bool _isPrime(int i)
{
int j;
int t = sqrt(i) + 1;
for (j=2; j<=t; ++j) {
if (i % j == 0)
return false;
}
return true;
}
static ERL_NIF_TERM findPrime(ErlNifEnv *env, ERL_NIF_TERM nterm)
{
int n;
if (!enif_get_int(env, nterm, &n)) {
return enif_make_badarg(env);
}
else {
int i;
ERL_NIF_TERM res = enif_make_list(env, 0);
for (i=2; i<n; ++i) {
if (_isPrime(i)) {
res = enif_make_list_cell(env, enif_make_int(env, i), res);
}
}
return res;
}
}
static ErlNifFunc nif_funcs[] = {
{"findPrime", 1, findPrime}
};
// 宏第一个参数对应着模块名,会被宏自动转换成字符串
ERL_NIF_INIT(prime, nif_funcs, NULL, NULL, NULL, NULL)
编译:
gcc -O3 -fPIC -bundle -flat_namespace -undefined suppress -fno-common -Wall nifprime.c -o nifprime.so -I/usr/local/lib/erlang/usr/include
-module(prime).
-export([load/0, start/2]).
% 装载Native C
load() ->
erlang:load_nif("nifprime", 0).
start(M, N) ->
statistics(runtime),
L = findPrime(M, 1, N, []),
{_, T} = statistics(runtime),
io:format("total running time: ~p ms ~n", [T]),
io:format("found primes number: ~p~n", [length(L)]).
findPrime(N) ->
% NIF装载后执行Native C程序,若不装载则执行下面的Erlang程序
findPrime(a, 1, N, []).
findPrime(_, N, N, L) ->
L;
findPrime(a, X, N, L) ->
case isPrimeInt(X, 2, trunc(math:sqrt(X) + 1)) of
true -> findPrime(a, X+1, N, [X|L]);
_ -> findPrime(a, X+1, N, L)
end;
findPrime(z, _X, N, _L) ->
findPrime(N).
isPrimeInt(1, _, _) -> false;
isPrimeInt(2, _, _) -> true;
isPrimeInt(X, N, E) when N =< E ->
case X rem N of
0 -> false;
_ -> isPrimeInt(X, N+1, E)
end;
isPrimeInt(_, _, _) -> true.