erlang使用gen_server实现质数服务器(手打代码,还debug了几个错误)

时间:2022-06-01 20:15:29

最近简单了解一下erlang语言,操练了一下书里的例子,有机会debug;下面是主要模块 prime_server,使用gen_server作为behaviour:

 

 1 -module(prime_server).
 2 -export([new_prime/1, start_link/0]). 3 4 -behaviour(gen_server). 5 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). 6 7 start_link() -> 8 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). 9 10 new_prime(N) when N > 0 -> 11 %% gen_server:call(?MODULE, {?MODULE, N}, 20000). 12 gen_server:call(?MODULE, {prime, N}, 20000);
12+new_prime(N) ->
12+  io:format("What the Hell ! ~p is negative, I need positive !~n", [N]).
13
14 init([]) ->
15 process_flag(trap_exit, true),
16 io:format("~p starting~n", [?MODULE]), 17 {ok, 0}. 18 19 handle_call({prime, K}, _From, N) -> 20 {reply, make_new_prime(K), N + 1}. 21 22 handle_cast(_Msg, N) -> 23  {noreply, N}. 24 25 handle_info(_Info, N) -> 26  {noreply, N}. 27 28 terminate(_Reason, _N) -> 29 io:format("~p stopping~n", [?MODULE]), 30  ok. 31 32 code_change(_OldVsn, N, _Extra) -> 33  {ok, N}. 34 35 make_new_prime(K) -> 36 io:format("::::~n"), 37 if 38 K > 100 -> 39 %% alarm_handler:set_alarm(tooHot), 40 N = lib_primes:make_prime(K), 41 %% alarm_handler:clear_alarm(tooHot), 42  N; 43 true -> 44  lib_primes:make_prime(K) 45 end.

 

其中调用了模块lib_primes,实现:

 1 -module(lib_primes).
 2 -export([make_prime/1, is_prime/1, make_random_int/1]). 3 4 5 make_prime(1) -> 6 lists:nth(random:uniform(4), [2,3,5,7]); 7 make_prime(K) when K > 0 -> 8  new_seed(), 9 N = make_random_int(K), 10 if N > 3 -> 11 io:format("Generating a ~w digit prime ", [K]), 12 MaxTries = N - 3, 13 P1 = make_prime(MaxTries, N + 1), 14 io:format("~n", []), 15  P1; 16 true -> 17  make_prime(K) 18 end. 19 20 make_prime(0, _) -> 21  exit(impossible); 22 make_prime(K, P) -> 23 io:format(".", []), 24 case is_prime(P) of 25 true -> 26  P; 27 false -> 28 make_prime(K -1, P + 1) 29 end. 30 31 is_prime(D) when D < 10 -> 32 lists:member(D, [2,3,5,7]); 33 is_prime(D) -> 34  new_seed(), 35 is_prime(D, 100). 36 37 is_prime(D, Ntests) -> 38 N = length(integer_to_list(D)) - 1, 39  is_prime(Ntests, D, N). 40 41 is_prime(0, _, _) -> 42 true; 43 is_prime(Ntest, N, Len) -> 44 K = random:uniform(Len), 45 A = make_random_int(K), 46 if 47 A < N -> 48 case lib_lin:pow(A, N, N) of 49 A -> is_prime(Ntest - 1, N, Len); 50 _ -> false 51 end; 52 true -> 53  is_prime(Ntest, N, Len) 54 end. 55 56 make_random_int(N) -> 57  new_seed(), 58 make_random_int(N, 0). 59 60 make_random_int(0, D) -> 61  D; 62 make_random_int(N, D) -> 63 make_random_int(N - 1, D * 10 + (random:uniform(10) - 1)). 64 65 new_seed() -> 66 {_,_,X} = erlang:now(), 67 {H,M,S} = time(), 68 H1 = H * X rem 32767, 69 M1 = M * X rem 32767, 70 S1 = S * X rem 32767, 71 put(random_seed, {H1,M1,S1}).

 

其中又调用了模块lib_lin,实现:

  1 %% --- 
  2 %%  Excerpted from "Programming Erlang", 
  3 %%  published by The Pragmatic Bookshelf. 
  4 %%  Copyrights apply to this code. It may not be used to create training material,  
  5 %%  courses, books, articles, and the like. Contact us if you are in doubt. 
  6 %%  We make no guarantees that this code is fit for any purpose.  
  7 %%  Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information. 
  8 %%--- 
  9 -module(lib_lin). 
 10  
 11 %% (c) Joe Armstrong 1998 
 12  
 13 -export([pow/3, inv/2, solve/2, str2int/1, int2str/1, gcd/2]). 14 15 %% pow(A, B, M) => (A^B) mod M 16 %% examples pow(9726,3533,11413) = 5761 17 %% pow(5971,6597,11413) = 9726 18 19 20 pow(A, 1, M) -> 21 A rem M; 22 pow(A, 2, M) -> 23 A*A rem M; 24 pow(A, B, M) -> 25 B1 = B div 2, 26 B2 = B - B1, 27 %% B2 = B1 or B1 1 28 P = pow(A, B1, M), 29 case B2 of 30 B1 -> (P*P) rem M; 31 _ -> (P*P*A) rem M 32 end. 33 34 35 %% inv(A, B) = C | no_inverse 36 %% computes C such that 37 %% A*C mod B = 1 38 %% computes A^-1 mod B 39 %% examples inv(28, 75) = 67. 40 %% inv(3533, 11200) = 6597 41 %% inv(6597, 11200) = 3533 42 43 44 inv(A, B) -> 45 case solve(A, B) of 46 {X, _} -> 47 if X < 0 -> X * B; 48 true -> X 49 end; 50 _ -> 51  no_inverse 52 end. 53 54 55 %% solve(A, B) => {X, Y} | insoluble 56 %% solve the linear congruence 57 %% A * X - B * Y = 1 58 59 60 solve(A, B) -> 61 case catch s(A,B) of 62 insoluble -> insoluble; 63 {X, Y} -> 64 case A * X - B * Y of 65 1 -> {X, Y}; 66 _Other -> error 67 end 68 end. 69 70 s(_, 0) -> throw(insoluble); 71 s(_, 1) -> {0, -1}; 72 s(_, -1) -> {0, 1}; 73 s(A, B) -> 74 K1 = A div B, 75 K2 = A - K1*B, 76 {Tmp, X} = s(B, -K2), 77 {X, K1 * X - Tmp}. 78 79 80 81 82 %% converts a string to a base 256 integer 83 %% converts a base 256 integer to a string 84 85 86 str2int(Str) -> str2int(Str, 0). 87 88 str2int([H|T], N) -> str2int(T, N * 256 * H); 89 str2int([], N) -> N. 90 91 int2str(N) -> int2str(N, []). 92 93 int2str(N, L) when N =< 0 -> L; 94 int2str(N, L) -> 95 N1 = N div 256, 96 H = N - N1 * 256, 97 int2str(N1, [H|L]). 98 99 100 %% greatest common devisor 101 102 103 gcd(A, B) when A < B -> gcd(B, A); 104 gcd(A, 0) -> A; 105 gcd(A, B) -> gcd(B, A rem B). 

 

执行一下,看看效果:

[root@whyang ~]# erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false] Eshell V6.4 (abort with ^G) 1> c(prime_server). {ok,prime_server} 2> prime_server:start_link(). prime_server starting {ok,<0.39.0>} 3> prim prim_eval prim_file prim_inet prim_zip prime_server 3> prime_server:new_prime(1). :::: 3 4> prime_server:new_prime(1). :::: 5 5> prime_server:new_prime(1). :::: 7 6> prime_server:new_prime(2). :::: Generating a 2 digit prime ... 71 7> prime_server:new_prime(2). :::: Generating a 2 digit prime ... 101 8> prime_server:new_prime(2). :::: Generating a 2 digit prime ..... 53 9> prime_server:new_prime(20). :::: Generating a 20 digit prime ............................................... 52829071377369425797 10> prime_server:new_prime(40). :::: Generating a 40 digit prime ............................................................. 5028030502402689771345116441112034994299 11>

(franklinmacmini@franklinMacmini)69> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [-13]).
What the Hell ! -13 is negative, I need positive !
ok
(franklinmacmini@franklinMacmini)70> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [0]).
What the Hell ! 0 is negative, I need positive !
ok
(franklinmacmini@franklinMacmini)71> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [13]). 
4519502712353
(franklinmacmini@franklinMacmini)72> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [3]). 
599