建立一个OTP应用
http://www.javaeye.com/topic/374167
以下是在erlang项目开发中的一些记录,即包含很多通俗易懂的原则,也包含一些似是而非的建议,比较混乱,还没有积累到一个可以分门别类的地步,各位就将就看吧..
:)
* 确保没有任何编译警告
* Erlang中String采用list实现,32位系统中,其1个字符用8个字节的空间(4个保存value, 4个保存指针)。因此string速度较慢,空间占用较大
* 在Server中,总是尽力书写尾递归(tail-recursive)的函数
* 使用'++'时,left list会被拷贝,然后添加到right list的头部,因此最好把length较短的list放在左侧
* 避免使用regexp,如果需要正则表达式,请使用re
* timer模块的大部分函数实现,依赖于一个process,如果过多使用timer,会导致这个process负载过大,影响效率。
推荐使用erlang:send_after/3及erlang:start_timer/3
* 避免使用list_to_atom/1,因为erlang中atom数量最大为1048576, 且不进行GC控制。因此如果持续性的调用list_to_atom/1
可能很容易达到系统上限,从而导致emulator terminate。请使用list_to_existing_atom/1。
* list内部实现为一个列表,因此length(List), 需要遍历整个list比较耗时
* 对于不同的数据类型,使用不同的size函数:tuple_size/1, byte_size/1, bit_size/1
* 使用binary match来进行binary的分割,而不使用split_binary/2
* 如果两个list都拥有很多数据,那么请不要使用'--',而是将数据转化到ordsets,然后调用ordsets:substract/2.
* 对于binary相关操作可以进行binary优化(bin_opt_info编译选项)代码框架:
* f(<<Pattern1,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
f(<<Pattern2,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
...
f(<<>>, ...) ->
ReturnValue.
* 调用lists:flatten/1可以将list扁平化,这个操作代价很大,比'++'还要昂贵。下面这些时候我们可以避免:
将数据发送给port时
调用list_bo_binary/1和iolist_to_binary前
* 小的函数可以让您方便的找出错误的函数和代码
* 不要在同一行出现相同的符号
20 some_fun() ->
21 L = [{key1, v1}, {key2, [some_record#v21, v22]}],
22 ...
编译时,会提示line 21 '[' 语法错误, 因为21行有多个 '[' ,所以这个bug不能准确定位,你需要花时间去排查代码。
好的做法是:
20 some_fun() ->
21 L = [{key1, v1},
22 {key2, [some_record#v21, v22]}
23 ],
...
这样,编译其会提示你 line 22 '[' 语法错误,你很开就知道是那个地方错了。
* 使用 CTRL + \ 或 init:stop(), 可以退出Erlang, 使用CTRL + G 及 CTRL + C 弹出菜单选项,可以选择是否退出Erlang。
其中CTRL + G可以用来连接其他的shell, CTRL + C可以查看其他一些系统信息
Ctrl + C abort 是野蛮的退出方式
* use "open_port({fd,0,2}, [out])" make erlang program write standard error to unix system
* If you don't run experiments before you start designing a new system, your entire system will be an experiment!
* standard data structure desc:
Module Description
sets sets, i.e. a collection of unique elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative arrays
ets hash tables and ordered sets (trees)
dets on-disk hash tables
Suggestion:
elments count: 0 - 100 | 100 - 10000 | 10000 -
our select : list | ets | gb_tree
* 通过code:clash/0 检测代码中是否有module冲突现象(sticky)
* epmd -d -d 启动 epmd 可以查看erlang node之间的通讯
* 将正常的逻辑代码和错误处理代码分离,发生错误时,尽管错误。由另一个错误处理模块进行处理
* 类似于操作系统,我们的程序也可以分为kernel 和 user 两层, 对于kernel绝对不能出现错误, 对于user可以出现错误,进行恢复
* process顶层loop涉及的代码及函数,最好在一个module中实现
* process 的register name和module名称一致, 便于寻找代码
* 每个process具有一个单一的角色,比如:supervisor 用来进行错误恢复, work 工作者,可以出现错误, trusted worker 不会出现错误
* 通过函数调用可以实现的功能,就不要使用sever实现(如gen_server, 及类似的loop 实现)
* 给消息加一个tag,在发生错误的时候,可以定位到消息,同时也有利于程序的稳健
* 在消息循环中,对于unknown的消息,请调用lib:flush_receive/0 将其清除,减轻process msg queue的长度
* server中总是书写尾递归的循环
* 尽量使用record, 而不是原始的tuple来表现数据结构, 在使用record时,使用select match:
#person{name = Name, age = Age} = Person
* 对于返回值,最好也添加一个tag,用来说明返回值类型,或者执行成功与否
* 尽可能少的使用catch和try,在erlang程序中,不推荐主动捕获异常。只有当我们的逻辑特别复杂,我们可以使用throw来返回数据,使用catch来获取返回值。
* 当然程序与外界交互,外界数据不可靠时,需要使用catch和try
* 慎重使用process dictory, 当你使用get/1, put/1时,你的应用会具有很大的slide effect。可以通过加入一个新的参数来保存原本需要存储到process dictory中数据
* 如果不想使自己糊涂,请不要使用import
* 使用export时,将功能类似的接口组合在一起,并添加合理的注视,这样你的接口更清晰,别人使用起来更方便
* 不要书写嵌套太深的代码
* 不要书写太长的module
* 不要书写太长的函数
* 每行代码不能太长
* 避免使用 "_" 匿名变量,请为每个变量选择有意义的名称,如够某个变量暂时不使用,请以下划线 "_" 开始
* {error, enfile} enfile error in socket 是以为内linux系统中 ulimit 限制, 在root下修改:ulimit -n 25000
* {error, enotconn} 表示socket已经关闭
* 在erlang开发时,慎重使用macro,因为erlang的single assign的缘故,同时调用某个marco,而macro又定义了某个变量,可能导致badmatch错误。
比如:
-define(ADDLINEINFO1(F),
(
begin
Str1 = lists:concat(["[Mod:", ?MODULE, " Line:", ?LINE, "]"]),
Str1 ++ F
end
)).
-define(WARN(Log, F, D), log4erl:warn(Log, ?ADDLINEINFO(F), D)).
如果连续使用 WARN, 会出现此错误
* erlang中可以定义很多环境变量:
ERL_MAX_ETS_TABLES 设置最大的ets数目 默认1400
ERL_MAX_PORTS erlang最大的port数目 默认1024
* .app文件中的start_phases, 选项既可以用来作为include applications之间的同步启动,也可以用来对单个application进行分布启动。
顺序如下
包含included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
=> incl_app_cb:start_phase(go, normal, [])
ok
无included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
ok
* 任何时候,都要重视函数的返回值,通过match确保您的预期,如果发生错误,那么就大胆的表达出来。
建立一个OTP应用的更多相关文章
- linux建立一个快捷方式,连接到另一个目录
sudo ln -s 源目录 目标快捷方式比如你要在/etc下面建立一个叫LXBC553的快捷方式,指向/home/LXBC,那就是sudo ln -s /home/LXBC /etc/LXBC553
- [转]使用Scrapy建立一个网站抓取器
英文原文:Build a Website Crawler based upon Scrapy 标签: Scrapy Python 209人收藏此文章, 我要收藏renwofei423 推荐于 11个月 ...
- Windows下用Codeblocks建立一个最简单的DLL动态链接库
转自:http://blog.csdn.net/wangwei_cq/article/details/8187576 来源:http://hi.baidu.com/hellosim/item/9ae4 ...
- 【转】如何建立一个样式新颖的CSS3搜索框
在线演示 搜索框大概是web开发中最常用的UI元素之一,我想基本没有必要去介绍如何使用它.无论是网站还是web应用,都会为了增强用户体验而添加它,那么你是不是也想过设计一个别致的搜索框? 在今天的文章 ...
- 如何建立一个完整的游戏AI
http://blog.friskit.me/2012/04/how-to-build-a-perfect-game-ai/ 人工智能(Artificial Intelligence)在游戏中使用已经 ...
- OSG入门即osgEarth建立一个地球的详细步骤
OSG入门即osgEarth建立一个地球的详细步骤 转:http://blog.csdn.net/xiaol_deng/article/details/9246291 最近在学习有关osg的知识,刚开 ...
- time模块目录下自己建立一个名为log的文件夹
使用python调用ping命令,然后在日志中记录ping的结果,用来监测网络连通情况. 代码: [python]from time import *from subprocess import *w ...
- 如何快速建立一个测试资源Web服务器及异步获取资源(Unity3D)
背景 1.最近看了几位专栏作家的文章,几篇提到了资源通过网络的动态获取.如何建立一个快速的测试环境,不免是一个问题,也就最简单的就是假设http服务器了,微软系的当然首选的IIS了,别的也能用阿帕奇或 ...
- 2.每人自己建立一个HelloWorld项目,练习使用git的add/commit/push/pull/fetch/clone等基本命令。比较项目的新旧版本的差别。答题人:张立鹏
第1步:创建SSH Key.在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步.如果没有,打开Shell ...
随机推荐
- Spring学习总结(7)——applicationContext.xml 配置文详解
web.xml中classpath:和classpath*: 有什么区别? classpath:只会到你的class路径中查找找文件; classpath*:不仅包含class路径,还包括jar文件 ...
- amazeui学习笔记--css(常用组件4)--关闭按钮Close
amazeui学习笔记--css(常用组件4)--关闭按钮Close 一.总结 1.关闭按钮基本用法:关闭按钮样式,可以结合其他不同组件使用.对 <a> 或者 <button> ...
- java中那些已经有的好用轮子
后续补充 IOUtils http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/IOUtils.html ...
- Java设计模式——代理模式实现及原理
简介 Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术.生活中的方方面面都可以虚拟到代码中.代理模式所讲的就是现实生活中的这么一个概念:中介. 代理模式的定义:给某一个对象提 ...
- 常用的Windows命令
常用的Windows命令 explorer-------打开资源管理器 logoff---------注销命令 shutdown-------关机命令 lusrmgr.msc----本机用户和组 se ...
- 【例题 6-17 UVa 10562】Undraw the Trees
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟+递归 [代码] #include <bits/stdc++.h> using namespace std; con ...
- 【Codeforces Round #445 (Div. 2) C】 Petya and Catacombs
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 看看时间戳为i的点有哪些. 每次优先用已经访问过的点. 如果不行就新创一个点. 注意新创点的时间戳也是i. [代码] #includ ...
- android开发-获取wifi列表
近期博主在学frangment框架,因此想着想着就想通过listfragment完毕对wifi列表的获取. 好! 如今就不说废话了. 一.wifi的基础知识 在Android的官方文档中定义了例如以下 ...
- 搭建聊天机器人Bot Framework
Bot Framework 搭建聊天机器人 这周我来跟大家分享的是在Microsoft Build 2016上发布的微软聊天机器人的框架. 现如今,各种人工智能充斥在我们的生活里.最典型的人工智能产品 ...
- express 学习笔记(一)路由
先导入express: var express = require('express'); var app = express(); 1.路由方法: get, post, put, head, del ...