Erlang的原子(atom)在匹配中有着重要作用,它兼顾了可读性和运行效率。 通过atom,可以实现很多灵活高效的应用。

atom可以看作是给字符串生成了一个ID,内部使用的是ID值,必要时可以取出它的内容(字符串),例如用于打印输出。

atom 的 Eterm 除去 6 位的标签之外剩下的部分,就是 atom 在 Erlang 虚拟机中的索引,也就是一个整数值。在 Erlang 中,有关 atom 比较的操作只需要比较两个索引值即可,就是整数操作,因此非常高效。atom 本身是一个字符串,那么 atom 的索引是怎样对应上具体的字符串的呢?也就是需要实现字符串和索引值之间的互相映射,字符串和索引值都必须唯一,这显然需要使用散列表。Erlang 虚拟机内实现了一套通用的索引和散列表机制,atom 表就是这个机制的一个客户。下图是这套机制中关键数据结构之间的关系。

图中左侧是散列表部分,右侧是索引部分。先看左侧。这个散列表采用的是标准的数据结构教科书上的实现。查找的时候:通过散列函数计算被散列对象的散列值,然后对散列表的长度取模,得到图中左侧指针数组的索引,接下来运气好的话能直接得到查找的对象(封装在 HashBucket 中),运气不好的话可能查不到,或者发生碰撞进行线性搜索(例如图中通过散列值得到索引 2 的时候就发生了碰撞,需要线性搜索 HashBucket 中匹配的 hvalue)。插入的时候:同样是先计算散列值得到索引,然后看对应的指针是否已经有对象了,如果没有,则直接加入,如果有的话,则插入队列头部。散列表在扩容的时候,会选择下一个合适的大小(erts/emulator/beam/hash.c 文件中的 h_size_table 数组列出了散列表大小增长的序列,数组里面都是素数,但是基本上符合倍增的关系),把老表复制到新表,然后删除老表。当然,增长是有限制的,散列表大小不能超出 h_size_table 数组中指定的最大值。

图中右侧是索引部分。索引表实际上是指向被索引对象的指针的数组,被索引对象的索引值就是对应指针在数组中的自然顺序。由于事先无法确定具体的索引数目,所以索引表的大小是动态增长的,增长单位为一个索引块的大小,每个索引块中有固定数目的指针(例如 1024 个)。散列表中每插入一个新的对象的时候,设置索引表中最小的那个可用索引。如果新的索引超出了索引块的边界,那么分配一个新的索引块,并且更新索引块表中的指针。同样,索引表的增长也是有限度的,索引块表的指针用完了就不能再增长了。索引块表的长度是在创建索引表的时候设置的,所以理论上可以很大,不超出内存限制即可,但是实际中还要考虑散列表的大小,这两者是相互制约的。

描述了散列和索引的数据结构和实现之后,我们回到散列索引的客户——atom。由于散列和索引是通用的,所以散列表指向的对象是 HashBucket 数据结构,而索引表指向的是 IndexSlot 数据结构。为了将散列和索引结合起来,这两个数据结构是重叠的,HashBucket 在 IndexSlot 头部。具体客户在使用的时候,要把 IndexSlot 放在自己的头部,这样就把具体的对象和散列索引结合起来了(就好像原始的面向对象的实现)。 从图中可以看出,我们的 atom 数据结构除了上述结构之外,还包含了具体的字符串指针、长度以及编码信息。将这些信息串起来之后,我们就可以高效地在常量时间内查询 atom 是否已经存在,已经存在的 atom 的索引值是什么,某个索引值对应的 atom 是什么以及插入新的 atom。

另一个问题,向散列表插入元素的时候,散列表要负责分配对象的内存,而散列表是通用的,那么散列表怎么知道分配例如 atom 呢?解决方法是散列表中元素的分配、比较、释放以及散列值计算的操作都通过回调函数的方式提供给散列表。这里 atom 使用的散列函数是经典的 hashpjw 散列算法,这个算法是字符串散列常用的算法。

在一个 Erlang 节点内,atom 表是全局共享的,因此多个线程对 atom 表的访问是通过读写锁保护的。对 atom 表的操作绝大部分都是读操作,只有真正插入新的 atom 时的操作才是写操作,插入新 atom 的情况一般不频繁,而且也很少有多个线程争抢着插入新 atom 的情况,大部分情况都是试图插入 atom 但是发现其实已经存在了,因此 atom 表使用的读写锁是针对读操作优化的读写锁。使用针对读操作优化的读写锁时读锁的开销非常小,即使是在大量线程争用的情况下。

Erlang 中的 atom 表是不进行垃圾回收的,毕竟在程序员不滥用 atom 的情况下,atom 数目可以控制在合理范围内。而且跟踪每一个 atom 的引用状况会产生很大的开销。所以不要滥用 atom,把 atom 表塞满是把 Erlang 虚拟机 crash 掉的一种方法。目前默认的 atom 数目限制是 1048576(1024×1024),通过虚拟机的 +t 参数可以设置。

atom的实现文件位于erts/emulator/beam/atom.h atom.c  index.h index.c hash.h hash.c

本文内容转自:http://www.cnblogs.com/zhengsyao/p/3424539.html

Erlang中atom的实现的更多相关文章

  1. Erlang中atom的实现[转]

    转自: http://www.cnblogs.com/zhengsyao/p/3424539.html 在 Erlang 中,使用 atom 既方便又高效,我们就来看看 atom 是怎么实现的.ato ...

  2. erlang中的原子(atom)内部实现[转]

    转自: http://www.kongqingquan.com/archives/208#more-208 Erlang中的atom由通用hash表实现,虚拟机中atom最终的用数值表示,对应表中的下 ...

  3. Erlang中一些错误或者异常的标识

    erlang中错误大体分为四种: 1. 编译错误    2. 逻辑错误    3. 运行时错误    4. 用户代码生成的错误 编译错误,主要是编译器检测出的代码语法错误 逻辑错误,是指程序没有完成预 ...

  4. [erlang 001] erlang中的错误及异常处理

    一. erlang中的错误 1. 分类 1) 编译错误:主要是编译器检测出的代码语法错误: 2) 逻辑错误:是指程序没有完成预期的工作,属于开发人员的问题: 3) 运行时错误:是指erlang运行时抛 ...

  5. Socket的UDP协议在erlang中的实现

    现在我们看看UDP协议(User Datagram Protocol,用户数据报协议).使用UDP,互联网上的机器之间可以互相发送小段的数据,叫做数据报.UDP数据报是不可靠的,这意味着如果客户端发送 ...

  6. erlang中字符编码转换(转)

    转自:http://www.thinksaas.cn/group/topic/244329/ 功能说明: erlang中对各种语言的编码支持不足,此代码是使用erlang驱动了著名的iconv编码库来 ...

  7. Erlang中日志管理

    http://blog.sina.com.cn/s/blog_96b8a1540101317g.html 一.基本概念 在Erlang中,通过两个概念管理错误事情:事件管理器(event manage ...

  8. erlang中变量作用域

    http://erlangdisplay.iteye.com/blog/315452 _开头(包括_)在erlang可以是表明,这个变量可以存任意东西,就是我们常说的全匹配,_A一般来说就是表明这个东 ...

  9. Erlang中频繁发送远程消息要注意的问题

    http://avindev.iteye.com/blog/76373 注:这篇文章可能会有争议,欢迎提出意见 在Erlang中,如果要实现两个远程节点之间的通信,就需要通过网络来实现,对于消息发送, ...

随机推荐

  1. [翻译] AGPhotoBrowser 好用的图片浏览器

    AGPhotoBrowser  好用的图片浏览器 https://github.com/andreagiavatto/AGPhotoBrowser A photo browser for iOS6 a ...

  2. struts2 iterator 迭代标签只显示前五条记录

    <s:iterator value="#session.produceLists" var="produce" begin="0" e ...

  3. Eclipse点不出方法了

    window→preferences→java→editor→Content Assist→Advanced 然后选中右上方的所有 右下方选中一个即可.

  4. bat薪酬

    三大互联网巨头公司,百度腾讯跟阿里如何划分级别?薪资待遇又有多少?除非身居其位,否则很难探知,但是等你到那个位置知道了,却又不能说,至少不能在公 开场合谈论.接下来就为大家揭秘,百度.阿里与腾讯内部的 ...

  5. IDEA的注册

    步骤: license server -> 属性 -> 允许作为程序执行文件 即 chmod 777

  6. mac下使用brew安装java等应用

    可以使用brew安装很多应用,比如java,idea,iterms,sublime brew tap caskroom/versions 将会安装新的brew仓库源brew cask install ...

  7. OTL翻译(1) -- 说明

    说明 该文档说明的是4.0版本的ORACLE/ODBC和DB2-CLI模板库(OTL).OTL4.0(后面简称OTL)模板库是基于C++的模板的. OTL4.0是组合了C++的模板框架和OTL适配器. ...

  8. MongoDB学习笔记(五)--复制集 && sharding分片

    主从复制                                                                                       主从节点开启 主节 ...

  9. word图片自动编号与引用(转)

    http://blog.csdn.net/hunauchenym/article/details/5915616 用Word时,可能会遇到文中使用了大量的图片的情况,这时,若采用手动为图片编号的方法, ...

  10. 使用Gnupg对Linux系统中的文件进行加密

    GnuPG(GNU Privacy Guard或GPG)是一个以GNU通用公共许可证释出的开放源码用于加密或签名的软件,可用来取代PGP.大多数gpg软件仅支持命令行方式,一般人较难掌握.由于gpg软 ...