[Erlang]前人挖坑,后人还要进坑?(1)

??

1. 保护式(guard)中如果出错,不会报错,只会返回false!

case 1=:1 of
     true when not erlang:length(t) =:= 1 orelse true ->
           ok;
     _ ->
         error
end.

Result is:   error

保护式中对t (atom) 求length会出错,本应crash掉,但因为在保护式中,默认出错后结束此保护式计算并返回false,这也是为什么保护式不接受复杂的函数,只能用erlang的bif来做的原因之一。

2. try catch 时如果不写catch类型,默认为throw类型!

try_catch(Value) ->
    try
        case Value  of
            error -> erlang:error({error,plz_catch_me});
            throw -> erlang:throw({throw,oh_get_you});
            exit -> erlang:exit({exit,sorry_by_mistake})
        end
    catch
        T -> T
    end.

Result :

所以最好是:明确: Catch   throw:T –> {throw,T}; error:T –> {error,T}; exit:T –> {exit,T} end.

3. 在保护式中使用erlang:length/1要小心再小心!(要遍历列表,时间长度不定)

%%写成这样的耗时与列表长度成平方比:Do not do this
foo(List) when lenght(List) >0 ->
         do_something;
foo(_) ->
       done.
%%使用匹配模式来做可做到任意长度断定
better([One]) ->
       do_something_one();
better([One,Two]) ->
       do_something_two();
better([one,Two|_]) ->
       do_something_big();
better([]) ->
      do_something_empty()
end.

Tip:  如果要判定List是一个非空List 可用 case List of [_|_] –> do_something(); _ –> done end.

4. ++只是lists:append/2的一个别名:如果要用一定要确定 ShortList++LongList !(可记为长短的反义短长…每次用他我都会条件反射想一下)

%% DO NOT DO
naive_reverse([H|T]) ->
    naive_reverse(T)++[H];
naive_reverse([]) ->
    [].

which is the most inefficient way there is to reverse a list. Since the ++ operator copies its left operand, the result will be copied again and again and again... leading to quadratic complexity.

这是最没效率去反转一个list,”++“会复制左边的元素,这个会使复制多次,导致平方倍的复杂度。

但是另一方面:下面这种用法就好了:

 
%% OK
naive_but_ok_reverse([H|T], Acc) ->
    naive_but_ok_reverse(T, [H]++Acc);
naive_but_ok_reverse([], Acc) ->
    Acc.

这并不是一个是非常坏的尝试,每个列表元素只被copy一次,那增长的Acc是在++的右边的,他不会每次都被copy的

当然,最佳实践还是下面这种:

%% Best Do
vanilla_reverse([H|T], Acc) ->
    vanilla_reverse(T, [H|Acc]);
vanilla_reverse([], Acc) ->
    Acc.

这比上面的还要高效一点点,你根本不用去建造一个list元素,直接copy他就可以了(或者:如果编译器不把[H]++Acc重写为[H|Acc] ,那就更高效啦)。

5. receive 和case的区别很大,虽然写法类似:

case_test(Value) ->
    case Value of
        1 -> ok;
        2 -> error
    end.
receive_test(Value)when Value>2 ->
    PID = spawn(fun () ->
        receive
            {msg,1} ->
                ok;
            {msg,2} ->
                error
        end
    end),
    [begin PID ! {msg,ValueT} end ||ValueT<-lists:seq(3,Value)],
    PID.

Result:

从上面可以看出:

5.1 case如果没有匹配就会出错;

5.1 recieve 会在没有匹配消息时阻塞,只要信箱中没有匹配消息,就会在等待期间挂起,=有新消息到时才会被唤醒,每次执行时,receive会先检查最老的消息(位于队列头部),像在case表达式中那样尝试匹配,如果找不到,就会继续下一消息,如果与当前匹配成功,且保护式成立(如果有),此消息就会被移出信箱,同时子句对应的正文会被执行,如果一直没找到合适消息就会一直等待至超时(如果有的话,after Times).

6. erl 用-noshell –noinput 启动一个node时,看不到,又不能输入怎么调试?用-remsh参数

>erl -name [email protected] -setcookie 123456 -noshell -noinput

>erl -name [email protected] -setcookie  123456 -remsh [email protected]

%%注意起的节点叫foo哦,不是bob了!
[email protected]> nodes().
[email protected]127.0.0.1>[‘[email protected]‘]
[email protected]127.0.0.1>node().
[email protected]127.0.0.1>‘[email protected]‘

这里的坑在于:

6.1 在remote出来的节点上调用q(),2个节点都会退出!好可怕,所有最好把q()这个函数在user_default.erl里面重写,让他不要执行init: stop().

6.2 window下要用werl 代替erl;

6.3 erl支持自定义参数,比如你写erl –rmsh test 也是不会报错的,如果不小心写错了,就会查好久……..

Tip: 已 起A,B二个节点,要用A 控制B,可以在A中使用Ctrl+G  r  NodeA j  2操作  具体见:Learn some erlang remote shell.

7.如果有一个ArgList 是:从不可知道的地方传过来是这样子:”[test1,test2,test3]”,要怎么使用才能动态执行?

场景:知道方法调用的方法:Method 使用 erlang:apply(Module,Method,ArgList)调用产生结果,这时的ArgList是不符合格式:

%% String = "[test1,test2,4]."注意最后面的结束小句号!
string_to_args(String) ->
    {ok, Scan1, _} = erl_scan:string(String),
    {ok,P}=erl_parse:parse_exprs(Scan1),
    {value,Value,[]} = erl_eval:exprs(P, []),
    Value.

以上合适List中所有的参数都是绑定的:,如果是有Test1这样的变量,我也没试过,还没遇到这种需求

可以参考

8. erl 启动参数可以自己定义:如

>erl -test erlang1  -test hello -test1 test1

>init:get_argument(test).
{ok,[["erlang1"],["hello"]]

>init:get_arguments().
[{root,["C:\\Program Files\\erl6.0"]},
 {progname,["erl"]},
 {home,["C:\\Users\\**"]},
 {test,["erlang1"]},
 {test,["hello"]}]

8.1  不要把参数定义为string了:比如 “hello world”

8.2 如果这个是启动application启动用的,就不要指望用这个自定义的参数了,用config定义吧

Applications should not normally be configured with command line flags, but should use the application environment instead. Refer to Configuring an Application in the Design Principles chapter for details

9.使用RPC时一定要记得你是在distributed的,时刻关注你在那个进程!

比如:把rpc:call放在loop里面和外面会得到不一样的效率反馈,以下这例子的结果是等价的,但是第一种会发出很多的call,第二种只有一个call.


%%Example - Bad
[rpc:call(node, ets, lookup, [table, K]) || K <- ListOfKeys].

%%Example - Good
rpc:call(node, ?MODULE, get_data, [ListOfKeys, []]).
get_data([], Out) -> lists:reverse(Out);
get_data([K|ListOfKeys], Out) -> get_data(ListOfKeys, [ets:lookup(table,K)|Out]).

同理你可以自己改一下:[gen_server:call(Pid,{func,Fun})||Fun<- FunList].

总之要能一次发消息处理的就不要多次发啦.
10 不要构造超极大的terms(或者你不可控制大小的terms). 
具体就是如果要遍历ets里面所有的元素,用ets:tab2list/1得出来的结果可能什么非常大,这可怎么办啊!

%% 一次性也出所有元素:不要这样子做
bad_traverse_to_print() ->
    [begin print(Person) end||Person <- ets:tab2list(person)],
    ok.

%%从第一个一直遍历到最后一个:数据要从erts内部搬到process 当ets很大的时候就效率低
good_traverse_to_print() ->
    good_traverse_to_print2(ets:first(person)).

good_traverse_to_print2(‘$end_of_table‘) ->
    ok;
good_traverse_to_print2(Key) ->
    [Person] = ets:lookup(person,Key),
    print(Person),
    good_traverse_to_print2(ets:next(person,Key)).

%%分页:最佳实践使用ets:select match MatchSpec:ets内部实现了把matchspec编译成opcode 然后eval的时候把需要的数据才拷贝到process去 大大减少了数据量
best_traverse_to_print() ->
    case ets:match(person,‘$1‘,10) of
        {PersonList,‘$end_of_table‘} ->
            [begin print(Person) end|| [Person] <- PersonList];
        {PersonList,Key} ->
            [begin print(Person) end|| [Person] <- PersonList],
            best_traverse_to_print2(Key)
    end,
    ok.
best_traverse_to_print2(Key) ->
    case ets:match(Key) of
        {PersonList,‘$end_of_table‘} ->
            [begin print(Person) end|| [Person] <- PersonList];
        {PersonList,Key2} ->
            [begin print(Person) end|| [Person] <- PersonList],
            best_traverse_to_print2(Key2)
    end.

print(Person) ->
    io:format("Name~p     Phone:~p~n",[Person#person.name, Person#person.phone]),
    ok.

第10条和第9条是看似矛盾的,一个说如果可以一次处理完就不要分多次,一个是如果太大就要分多次!注意,如果一个消息体太大了,也要分多次哦。
时间: 2024-07-29 15:08:16

[Erlang]前人挖坑,后人还要进坑?(1)的相关文章

[Erlang]前人挖坑,后人还要进坑?(3)

?? 21.在生成随机数过程中一直使用: random:seed(erlang:now()). erlang:now()是可以一直递增的数,从不重复,但是不适合用于随机算法,最好使用下面这种: -spec get_random_num(integer()) -> integer(). get_random_num(Max) -> <<A:32, B:32, C:32>> = crypto:rand_bytes(12), random:seed({A,B,C}), ran

[转]前人挖坑,后人填坑—如何把那些bug挖掘出来

当我们放下一个项目转投下一个时,手头的东西就要转交给他人处理,或者..不再有人处理,可代码还在那里,搞不好你就引用了别人的东西,保不准哪天别人的代码里就爆出了个大 bug,当然这里的“别人”也可能是 你!我们既不希望自己是受害者,更不希望自己是施害者. 写代码不免出点bug,没有人可以保证自己写的代码不出问题,而那些没有被挖掘出来的bug,便成了后来者哭笑不得的坑... 这段时间公司全面 https 改造,涉及到域名的迁移,域名的迁移不是 nginx 做个映射就完事儿了,还有各种代码的去 sch

MonkeyRunner进坑——errors importing other modules

后知后觉,刚知道Android提供了MonkeyRunner这么个东西,能用来干嘛呢,官方文档介绍得很清楚.简单说,可以用Python程序通过API, installs an Android application or test package, runs it, sends keystrokes to it, takes screenshots of its user interface, stores screenshots on the workstation. 还提供了easy pac

最近进坑了DCS-3950双层交换机链路聚合配置整理

交换机A上1-2端口对应交换机B上3-4端口 PC1链接交换机A上23端口 PC2链接交换机B上24端口 命令如下: DCS-3950-28C>enDCS-3950-28C#conDCS-3950-28C(config)#hostname switchAswitchA(config)#%Jan 01 00:01:39 2006 %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet1/2, changed state to DOWN%Ja

致成长——毕业一周年

转眼2015年已过半载,想来自己也已经毕业满一年了,从2013年12月到现在,进公司也有一年过半的时间了,期间从实习生,到试用期,再到转正,这么一路过来,却也过得飞快........ 一直想找个时间,给自己一个总结,也许这种事情本来就应该伴随在生活当中,但是不得不承认,人都是有惰性的,尤其我这种拖延症患者,还好,这个总结来得也不算迟. 2014年七月,拿到毕业证,摘掉了实习生的帽子,终于算是步入社会的“大人”了,有任务出差湖北,一行三人,对于刚毕业的我们来说,这算是新鲜事了,第一次出差,第一次来

Windows10(UWP)下的MEF

前言 最近在帮一家知名外企开发Universal Windows Platform的相关应用,开发过程中不由感慨:项目分为两种,一种叫做前人栽树后人乘凉,一种叫做前人挖坑后人遭殃.不多说了,多说又要变成月经贴了. 讲讲MEF. MEF全称Managed Extensibility Framework.我们做.Net的碰到依赖注入(DI:Dependency Injection)这一块的内容,一般会选择使用Unity或者MEF,这也是Prism主要使用的两种方式.在.Net 4.0之前,MEF一直

升讯威微信营销系统开发实践:(2)功能设计与架构设计

微信开发系列教程,将以一个实际的微信平台项目为案例,深入浅出的讲解微信开发.应用各环节的实现方案和技术细节. 本系列教程的最终目标是完成一个功能完善并达到高可用性能指标的微信管理软件,所以除了与微信本身紧密相关的对接和应用技术,还会讲到其它相关的所有知识点,从技术选型,架构设计,数据层的设计,API的设计,数据传输协议的设计,再到细节的前端的设计及技术应用,后台开发中的各方面技术,都会涉及.同时,在架构设计中,会考虑到运维领域的诸多问题,会涉及到部署环节中负载均衡及CDN分发,服务器流量及带宽控

给割边割点跪了

坑的事情不是知道教程有坑,是知道有坑之后以为大神改了再次跳进去. 我怀疑刘神是故意坑蒟蒻[不,刘神绝对是故意坑蒟蒻]... 两道题都是看着网上的代码a的,伪代码还不如程序代码看着容易...这绝对是惨绝人寰道德沦丧的悲剧啊喂... 大神们说着修路反而撒玻璃碴子之类的事情简直心痛QAQ 看教程不如直接看代码懂得快QAQ贵机房真是个神奇的地方,鹅妹子嘤 前人挖坑后人自杀 割点 上面是教程下面是代码 http://www.cnblogs.com/en-heng/p/4002658.html http:/

流控算法

漏桶算法 令牌桶算法 一年一度的「双 11」又要到了,阿里的码农们进入了一年中最辛苦的时光.各种容量评估.压测.扩容让我们忙得不可开交.洛阳亲友如相问,就说我搞双十一. 如何让系统在汹涌澎湃的流量面前谈笑风生?我们的策略是不要让系统超负荷工作.如果现有的系统扛不住业务目标怎么办?加机器!机器不够怎么办?业务降级,系统限流! 正所谓「他强任他强,清风拂山岗:他横任他横,明月照大江」,降级和限流是大促保障中必不可少的神兵利器,丢卒保车,以暂停边缘业务为代价保障核心业务的资源,以系统不被突发流量压挂为