1 rr的是使用:erlang中经常会进入debug模式去查找某个ets的信息,一般ets都是由record来定义结构的,但是在debug模块下不方便去查看某个record的定义,这时候可以使用命令rr(ModuleName) 来查看该module中用到的record, 再使用rl(RecordName)就可以查看了
看定义
rr(Module)
Reads record definitions from a module's BEAM file. If there are no record definitions in the BEAM file, the source file is located and read instead. Returns the names of the record definitions read. Module is an atom.
rr(Wildcard)
Reads record definitions from files. Existing definitions of any of the record names read are replaced. Wildcard is a wildcard string as defined in filelib(3) but not an atom.
2 怎么重启一个没有注册的进程,erlang中如果进程没有使用register或者通过gen_server等启动,没有注册,那么该进程只有一个进程id, 在shell中不好重启一个单独的进程,那么使用
PidList = erlang:processes()获取所有进程,再数进程位置n, 再用Pid = list:nth(n, PidLIst). 再调用exit(Pid, Reason).就可以结束了(目前只想到这种笨方法)
(后记:加入进程是<0.57.0>, 那么也可以用pid(0,57,0)来代表进程的pid)
3 关于process_flag(trap_exit, true).
process_flag(trap_exit, Boolean)
When trap_exit is set to true, exit signals arriving to a process are converted to {'EXIT', From, Reason} messages, which can be received as ordinary messages. If trap_exit is set to false, the process exits if it receives an exit signal other than normal and the exit signal is propagated to its linked processes. Application processes should normally not trap exits.
当设置这个参数之后,进程收到的退出的信号会被转化,可以接收,从而可以根据自己的需要来处理,如果不设置会受到相关信号会导致进程退出((normal信号除外))。
当两个有相互连接关系的进程,在退出时候会给彼此发送推出信号;
关于exit(Pid, Reason) -> true
Types:
Pid = pid()
Reason = term()
Sends an exit signal with exit reason Reason to the process Pid.
The following behavior apply if Reason is any term except normal or kill:
If Pid is not trapping exits, Pid itself will exit with exit reason Reason. If Pid is trapping exits, the exit signal is transformed into a message {'EXIT', From, Reason} and delivered to the message queue of Pid. From is the pid of the process which sent the exit signal. See also process_flag/2.
If Reason is the atom normal, Pid will not exit. If it is trapping exits, the exit signal is transformed into a message {'EXIT', From, normal} and delivered to its message queue.
If Reason is the atom kill, that is if exit(Pid, kill) is called, an untrappable exit signal is sent to Pid which will unconditionally exit with exit reason killed.
要注意信号normal和kill, 像进程发送退出信号,当信号为normal时候不会退出(不管是否设置trap_exit),
当信号为kill时候无条件退出(无论进程是否设置trap_exit)
exit(Pid, normal).
exit(Pid, kill).
4 register
使用register(Atom, Pid), 注册进程, unregister(Atom)来取消注册, 使用registered(), 来查看已经注册的名字, whereis(Atom), 来查看进程是否注册,注册就返回Pid, 否则返回 undefined
5 关于spawn
其实spawn和spawn_link 并没有什么奇怪的,但是审spawn的使用却有很多注意点,很可能会影响热更新,因为一个模块在erlang中只允许最多两个版本, 当有存在更多的版本时候,任何前两个版本的进程都会被结束掉, 如果使用spawn(M, F, A), 就会避免这种情况
erlang中重要的进程最好使用gen_server来做,或者用spawn的时候,要注意来监控这个进程,否则,在更新后,会由于把老版本kill掉的原因,时那个进程死掉,我就有一个进程是用来进行数据上报的,是用spawn起的,没有监控,总会莫名的挂掉,现在才发现是上面的原因造成的, 用spawn时候,可以起个进程通过link连接两个进程,然后通过receive来接受消息判断进程是否退出,例如
%% process monitor
on_exit(Pid) ->
spawn(fun () ->
process_flag(trap_exit, true),
link(Pid),
receive
{'EXIT', Pid, Why} ->
?EMSG(["pg2 exit, Reason=", Why]),
NewPid = spawn(?MODULE, loop, []),
[Node | _Ret] = get_other_node(),
on_exit(NewPid),
pg2:join(Node, NewPid)
end
end).
总之使用spawn或者spawn_link,大多情况有三种:
不关心创建进程是否退出: Pid = spawn(fun() -> ... end).
创建进程消失,我也消失,Pid = spawn_link(fun() -> ... end).
第三种,就是上面的exit的例子
6 erlang debug模式的重定向
rp() 之后的结果重定向就可以了
Eshell V5.9 (abort with ^G)
1> 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|...]
2> {ok, F} = file:open("dump.data", [write]).
{ok,<0.35.0>}
3> group_leader(F, self()).
4> rp(v(1)).
5>
然后就可以看到 dump.data里面的内容就是rp(v(1)), 并且任何内容都可以重定向到文件里面
如果在重定向完成,还想回到原来的shell终端,正常显示,可以这样,
在改变group_leader之前就找到自己的G = group_leader(), 保存原来的group_leader
然后再次改变自己的group_leader,
执行group_leader(M, self()).ok 重新回到了自己的终端
或者直接执行exit(self(), ffff). 退出当前终端,再启动新终端
group_leader的详细解释见
http://www.cnblogs.com/me-sa/archive/2012/02/26/erlang0041.html
当然不用这种重定向也是可以的,利用io:format,看定义,
format(IoDevice, Format, Data) -> ok
IoDevice = device()
device() = atom() | pid()
Either standard_io, standard_error, a registered name, or a pid handling IO protocols (returned from file:open/2).
所以可以用
{ok, P} = file:open("dump.data", [write]).
io:format(P, "~p", [term()]),这样也可以写入文件
7 module_info
在debug模式下经常要手动调用函数,很多函数不知道名字或者是否导出,使用Moudle:module_infoI(), 就可以看到导出了哪些函数可以方便使用,最好不要随便导出不用的函数,如果要调试就加上-compile(export_all).
8 宏 erlang常使用宏
-module(m).
-ifdef(debug).
-define(LOG(X), io:format("{~p,~p}: ~p~n", [?MODULE,?LINE,X])).
-else.
-define(LOG(X), true).
-endif.
编译方法
% erlc -Ddebug m.erl
or
1> c(m, {d, debug}).
{ok,m}
来自http://www.cnblogs.com/me-sa/archive/2011/07/20/erlang0006.html
8 关于容错
erlang中容错的核心思想就是link,就是一个进程监控另一个进程,otp也是这个思想,整个erlang系统也是这个思想,就是用一台机器来监视另外一台机器
监视器 单向监控,monitor
9 erlang两个节点的cookie不同的时候,可以通过set_cookie()来手动设置为相同,而不必重新启动设置
10 add_path
在自己写测试例子的时候经常会用到 不同的目录,加载其他目录的模块, 如果要切换目录有时候是很麻烦的事,
已经在终端上敲了很多命令了,如果所有命令全部再敲一遍当然很浪费时间,使用
code:add_path(Path). 就可以轻松搞定
11 查看一个gen_event中注册了 什么事件
gen_event:which_handlers(error_logger).
12 rebar和宏:
早知道erlang 编译可以用 -Ddebug参数,但是却不知道rebar怎么用, 搜了很多都搜不到,
用英文终于找到了,看来学习一门新语言,不学英语真心不行啊
用rebar编译带宏,只需要这样, 以宏名称为zzz为例
1用 ./rebar -Dzzz compile
2用 加入rebar.config {erl_opts, [{d, zzz}]}.
来自http://stackoverflow.com/questions/6808610/start-erlang-with-user-defined-variable-using-rebar
假设想定义宏 zzz=7可以用
http://riak-users.197444.n3.nabble.com/Rebar-user-defined-macro-td4025906.html
13 通过进程id获得node的名字
本来感觉pg2这个东西用途不大,最近发现这个函数,又感觉pg2的用途来了,多个node的进程全部加入pg2,要往哪个节点发送信息,可通过函数node(Pid) ->Node来获取是哪个节点的,看以下的函数
node(Arg) -> Node
Arg = pid() | port() | reference()
Node = node()
Returns the node where Arg is located. Arg can be a pid, a reference, or a port. If the local node is not alive, nonode@nohost is returned.
Allowed in guard tests.
nodes() -> Nodes
Nodes = [node()]
Returns a list of all visible nodes in the system, excluding the local node. Same as nodes(visible).
nodes(Arg | [Arg]) -> Nodes
Arg = visible | hidden | connected | this | known
Nodes = [node()]
Returns a list of nodes according to argument given. The result returned when the argument is a list, is the list of nodes satisfying the disjunction(s) of the list elements.
Arg can be any of the following:
visible
Nodes connected to this node through normal connections.
hidden
Nodes connected to this node through hidden connections.
connected
All nodes connected to this node.
this
This node.
known
Nodes which are known to this node, i.e., connected, previously connected, etc.
Some equalities: [node()] = nodes(this), nodes(connected) = nodes([visible, hidden]), and nodes() = nodes(visible).
If the local node is not alive, nodes(this) == nodes(known) == [nonode@nohost], for any other Arg the empty list [] is returned.
pg2有个小特性
If a member terminates, it is automatically removed from the group.
14 关于列表解析,
erlang中列表解析用的很频繁 ,看下面的列表,猜猜结果
[Q || [Q, N] <- [[1,1], [2,2], 3], _ <- lists:seq(1, N)].
为什么会是这个结果呢?
结果是[1,2,2]为什么呢,先看下个例子吧
[Q || Q <- [1,2], Q <- [3,4]].
结果是什么呢? 结果是[3,4,3,4],
先看一个learn you some erlang中的一个例子
5> [X+Y || X <- [1,2], Y <- [2,3]].
[3,4,4,5]
This runs the operations 1+2, 1+3, 2+2, 2+3. So if you want to make the list comprehension recipe more generic, you get: NewList = [Expression || GeneratorExp1, GeneratorExp2, ..., GeneratorExpN, Condition1, Condition2, ... ConditionM]. Note that the generator expressions coupled with pattern matching also act as a filter:
列表的一般形式是 [X || Qualifier1, Qualifier2]
Qualifier可以是生成器,也可以使过滤器, 如果是生成器时候,就会像矩阵,一样,来遍历,[Q || Q <- [1,2], Q <- [3,4]]. 中 显然是两个生成器,q的赋值为后者的值(我把它当做逗号运算来看,所以有两个值时候,选择后者),所以,结果就是[3,4,3,4]. 同样的道理使用于第一个例子
15 erlang问题topN,erlangqa上面的
http://erlangqa.com/598/erlang%E6%96%B0%E6%89%8B%E4%B8%8A%E8%B7%AF%E7%96%91%E9%97%AE-top-n?start=0#a_list_title
16 catch的使用
捕获异常的一种方式是使用catch原语, 当捕获一个异常时,这个异常会被转化为错误的一个元组,用法
9> catch (5/4).
1.25
12> catch 6/0.
{'EXIT',{badarith,[{erlang,'/',[6,0],[]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,576}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,360}]},
{shell,exprs,7,[{file,"shell.erl"},{line,668}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]}}
local_call(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
case catch apply(M, F, A) of
{'EXIT',_}=V -> {badrpc, V};
Other -> Other
end.
后者来自rpc.erl;
15 关于group_leader参考:
http://erlangdisplay.iteye.com/blog/336005
17 在tcp接受信息中,经常给某个socket设置inet:setopts(Sock, [{active, once}]);
{ok, Listen} = gen_tcp:connect(..),
{ok, Socket} = gen_tcp:listen(Listen),
loop(Socket).
loop(Socket) ->
receive
{tcp, Socket, Data} ->
....
inet:setopts(Socket, [{active, once}]),
loop(Socket);
{tcp_closed, Socket} ->
....
end.
这样半阻塞,防止消息被客户端淹没
18 登陆远程shell
可以在执行erl 的时候设置cookie, 执行erl -setcookie 'AAAAAAA'
按ctrl+G 可以开启远程shell ,
r NodeName 是开启远程shell
S NodeName 是开启本地shell
19如何找到堆积最长的进程
方法1:lists:foreach( fun(P)-> case erlang:process_info(P, message_queue_len) of {message_queue_len, Count} when Count > 1 -> io:format("~p~p~p ~p~n",[P,erlang:process_info(P, registered_name),erlang:process_info(P, current_function), erlang:process_info(P, message_queue_len)]); _ -> ok end end,erlang:processes()).
方法2,找到堆积最多的top 10
F=fun(Max)-> L=lists:keysort(2,[{{pid,P},erlang:process_info(P,message_queue_len)} ||P<- erlang:processes(),process_info(P,message_queue_len) > {message_queue_len,Max} ]), lists:reverse(lists:nthtail(length(L) - 10, L)) end.
F(10).
20 error浅谈
http://www.erlang.org/doc/reference_manual/errors.html
错误类型一般不会超过这几种,
错误如果是在进程中一般会导致进程的崩溃, 会常常伴有
exception exit: {function_clause, 像这样的语句,如果是单独在eshell中测试不会产生exception exit
一个不错的错误的例子
http://www.trapexit.org/forum/viewtopic.php?p=65767
关于crash report
2.3 Crash Report
Processes started with the proc_lib:spawn or proc_lib:spawn_link functions are wrapped within a catch. A crash report is issued whenever such a process terminates with an unexpected reason, which is any reason other than normal or shutdown. Processes using the gen_server and gen_fsm behaviours are examples of such processes. A crash report contains the following items:
Crasher.
Information about the crashing process is reported, such as initial function call, exit reason, and message queue.
Neighbours.
Information about processes which are linked to the crashing process and do not trap exits. These processes are the neighbours which will terminate because of this process crash. The information gathered is the same as the information for Crasher, shown in the previous item.
http://www.erlang.org/doc/apps/sasl/error_logging.html
21关于try catch
erlang中的任何东西都是表达式,表达式就有值,try end也不例外;
捕获异常有两种方式, 1 种是try catch表达式将一个会抛出异常的函数括号括起来,2是把函数调用包含在catch里面。
erlang里面一般有3种异常, error:R, exit:R, thrown:R, 他们分别对应 erlang:error(Why), exit(Why), thrown(Why)显示的产生一个错误, 如果程序中显式的写
thrown(Wyh)有必要添加注释说明产生异常原因,error(Why)经常用于产生意想不到的系统异常;
原始的捕获异常的方式
try FunOrExpression of
Pattern1 [when Gurd1] -> Expression1;
.......
catch
Exception:ExPattern [when Gurd1] -> ExExpression1;
.....
after
AfterExpression
end
afterExpression是无论如何都会被执行, 执行后表达式本身的值被忽略;
try catch常用几个简化版本:
try F
catch ..
end,
try F of
catch
...
end
出错几率较小的程序:
try my_fun(X)
catch
throw:{thisError, X} -> ...
throw:{someError, X} -> ...
end
my_fun(X) ->
case .... of
....
.... -> throw({thisError, ....})
.....-> throw({thisError, ....})
end
捕获所有的异常:
try Expr
catch
_:_ -> ....
end
或者
try Expr
catch
_ -> ...
end
两个相同的try catch例子
case (catch foo(...))) of
{'EXIT', Why} ->
...
Val ->
...
end
等价于
try foo(...) of
Val -> ....
catch
exit:Why ->
....
end