erlang 读取文件内容怎么读

erlang怎么发音? - 笑话 - Life - ITeye论坛
erlang怎么发音?
锁定老帖子
精华帖 (0) :: 良好帖 (0) :: 灌水帖 (0) :: 隐藏帖 (2)
来自: 柳州
发表时间:&&
相关知识库:
erlang怎么发音呢?
a. 恶狼
b. e,r,lang(前两个字母单独发音,然后lang)
c. er,lang(er发音,然后lang)
dennis_zane
等级: 资深会员
文章: 1530
积分: 2148
来自: 杭州
发表时间:&&
二郎,二郎神
请登录后投票
积分: 1329
来自: 天津
发表时间:&&
D语言(D- Lang)岂不应该叫“大郎”。。。武大郎
请登录后投票
jiyanliang
来自: 南京
发表时间:&&
顺便问一下Axis怎么发音阿
好像就一个 x 发音
请登录后投票
stevenwang
等级: 初级会员
来自: 北京
发表时间:&&
只有发出儿话音才对。
一般南方人都发e-,听起来很怪。
就像史湘云叫宝玉“爱”哥哥一个调调。
请登录后投票
发表时间:&&
咦,啊?狼!
请登录后投票
等级: 初级会员
来自: 上海
发表时间:&&
爱郎!!!
请登录后投票
等级: 初级会员
发表时间:&&
java加瓦,扎瓦,扎窝
请登录后投票
文章: 1547
积分: 2060
来自: 杭州
发表时间:&&
t0uch 写道erlang怎么发音呢?
a. 恶狼
b. e,r,lang(前两个字母单独发音,然后lang)
c. er,lang(er发音,然后lang)
以前是C,现在看起来还是你的恶狼比较好,哈哈
请登录后投票
跳转论坛:移动开发技术
Web前端技术
Java企业应用
编程语言技术966,690 十二月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
用Erlang实现领域特定语言
用Erlang实现领域特定语言
欲知区块链、VR、TensorFlow等潮流技术和框架,请锁定
相关厂商内容
前三行echo命令创建biz_rules.txt文件,并向其中写入三条规则。这些规则的逻辑很直白;其表达形式与直接从用户口中说出来的话相差无几。
buy 9000 shares of GOOG when price is less than 500
sell 400 shares of MSFT when price is greater than 30
buy 7000 shares of AAPL when price is less than 160
我们的DSL放在一个名为&dsl&的Erlang模块中,模块只有一个文件。在erl代码中,第一条命令是用内建的c函数编译并加载dsl模块。
1&c(dsl). % compiles and loads, assumes dsl.erl is in the current directory
产生一个Broker
dsl模块有个公共函数名为broker(译注:股票经纪人)。
broker() -&
{buy, Quantity, Ticker} -&
% 向外部系统下单的具体代码放在这里
Msg = &Order placed: buying ~p shares of ~p&,
io:format(Msg, [Quantity, Ticker]),
{sell, Quantity, Ticker} -&
% 向外部系统下单的具体代码放在这里
Msg = &Order placed: selling ~p shares of ~p&,
io:format(Msg, [Quantity, Ticker]),
broker函数等待消息并反复调用receive块。它只接收两类消息:卖出股票的消息和买入股票的消息。由于这里只是做一个演示,所以具体的下单操作就省略了。
请注意broker是尾递归的。在命令型(imperative)编程语言里,一般会用循环来达到相同目的。而在Erlang中不需要使用循环,因为尾递归函数会被自动优化在固定的空间中运行。Erlang开发者不需要承担手工管理内存的责职,可以远离&for&、&while&、&do&这些关键字。这三个关键字之于栈,就像是&malloc&和&dealloc&之于堆&&多余。
给仿真器的第二行命令是产生一个匿名函数的Erlang进程,并且返回进程ID。进程ID的值绑定到变量Pid。
2& Pid = spawn(fun() -& dsl:broker() end). % call broker in parallel
在Erlang里,匿名函数以 &fun& 关键字起头,&end& 关键字结尾。看到这些字眼的时候请留心,因为本文中将出现非常多的匿名函数。上面的这个匿名函数很简单,它仅仅包装了一下broker。
我们不打算深入讲解Erlang的众多有趣特性。暂且请将上述代码看作是产生了一条单独的执行路径,下文将称之为broker进程。内建的spawn函数返回了一个进程ID,我们将通过这个进程ID向该进程发出买卖单。
加载业务规则的第一种途径
接下来我们调用load_biz_rules,它是dsl模块的另一个公开函数。
3& Functions = dsl:load_biz_rules(Pid, &biz_rules.txt&).
传给load_biz_rules的参数是broker进程的ID和业务规则所在的文件;返回的是一个Erlang函数列表。本文将出现许多返回函数的函数,不熟悉函数式编程的人可能觉得理解起来有些障碍。请联想一下在面向对象的世界里,一个对象创建另一个对象并通过方法返回对象,是很寻常的事情&&甚至还有专门针对该情形的设计模式,比如抽象工厂模式。
load_biz_rules所返回的列表中每一个函数元素,都代表着先前写入到biz_rules.txt的一条业务规则。在面向对象编程语言里,我们大概会用一组对象实例来给这些规则建模;而在Erlang里,我们用函数。
load_biz_rules(Pid, File) -&
{ok, Bin} = file:read_file(File),
Rules = string:tokens(erlang:binary_to_list(Bin), &\n&),
[rule_to_function(Pid, Rule) || Rule &- Rules].
load_biz_rules函数首先将文件读入内存。文件的内容被分割放入一个字符串列表,然后绑定到名为Rules的变量。在Erlang中,函数的最后一行默认成为函数的返回值(和Ruby一样),并且总是以句号结尾。load_biz_rules的最后一行执行了一次列表推导(list comprehension),构建并返回一个函数列表。
熟悉列表推导的读者会知道Rule &- Rules部分是发生器(generator),而rule_to_function(Pid, Rule)部分是表达式模板(expression template)。这是什么意思?它的意思是我们创建一个新的列表,然后用Rules列表里的元素经过变换之后填充到新列表。 rule_to_function函数完成实际的变换工作。换句话说,最后一行的意思是&把broker进程的ID和Rules中的每一条Rule传递给 rule_to_function&&然后把rule_to_function返回的函数列一个表给我&。
rule_to_function(Pid, Rule) -&
{ok, Scanned, _} = erl_scan:string(Rule),
[{_,_,Action},{_,_,Quantity},_,_|Tail] = Scanned,
[{_,_,Ticker},_,_,_,{_,_,Operator},_,{_,_,Limit}] = Tail,
to_function(Pid, Action, Quantity, Ticker, Operator, Limit).
第一行代码将传给rule_to_function的Rule字符串扫描进一个元组(tuple)。接下来两行用模式匹配摘出实施规则所必需的数据。摘出来的值被绑定到Quantity、Ticker(译注:股票代码)等变量。接着broker进程的ID和摘出的5个值被传给to_function函数。 to_function将构建并返回代表着一条业务规则的函数。
我们将讨论to_function的两种实现,首先看一个比较偏向实用的版本。
to_function(Pid, Action, Quantity, Ticker, Operator, Limit) -&
fun(Ticker_, Price) -&
Ticker =:= Ticker_ andalso
( ( Price & Limit andalso Operator =:= less ) orelse
( Price & Limit andalso Operator =:= greater ) ) -&
Pid ! {Action, Quantity, Ticker}; % place an order
erlang:display(&no rule applied&)
这个to_function实现做了一件事&&返回一个匿名函数。匿名函数的参数是两项市场数据:股票代码和价格。传给该函数的股票代码和价格,将与业务规则中指定的股票代码及价格相比较。如果匹配上了,就用发送操作符(即!符号)向broker进程发送一则消息,告诉它下单。
加载业务规则的第二种途径
to_function的第二种实现学院味比较浓一些。它构造一种抽象形式的Erlang表达式,并返回一个匿名函数,让它以后再动态地求解。
to_function(Pid, Action, Quantity, Ticker, Operator, Limit) -&
Abstract = rule_to_abstract(Action, Quantity, Ticker, Operator, Limit),
fun(Ticker_, Price) -&
TickerBinding = erl_eval:add_binding('Ticker', Ticker_, erl_eval:new_bindings()),
PriceBindings = erl_eval:add_binding('Price', Price, TickerBinding),
Bindings = erl_eval:add_binding('Pid', Pid, PriceBindings),
erl_eval:exprs(Abstract, Bindings)
函数的第一行将脏活都委托给了rule_to_abstract函数。你不应该花太多时间研究rule_to_abstract,除非你是觉得Perl很对胃口的那种人。
rule_to_abstract(Action, Quantity, Ticker, Operator, Limit) -&
Comparison = if Operator =:= greater -& '&'; true -& '&' end,
[{clause,1,[],
'andalso',
{op,1,'=:=',{atom,1,Ticker},{var,1,'Ticker'}},
{op,1,Comparison,{var,1,'Price'},{integer,1,Limit}}}]],
{var,1,'Pid'},
{tuple,1,[{atom,1,Action},
{integer,1,Quantity},
{atom,1,Ticker}]}}]},
{clause,1,[],
[[{atom,1,true}]],
{remote,1,{atom,1,erlang},{atom,1,display}},
[{string,1,&no rule applied&}]}]}]}].
rule_to_abstract函数构造并返回一个抽象形式的Erlang控制结构。这个控制结构是由一系列具体限制条件组成的一个&if&语句。顺便一提,上面的抽象形式用了后缀运算符的写法,不同于一般Erlang语法的中缀写法。如果把它套用到单条规则上面,我们实际上是用编程的方式构建以下代码的抽象形式:
Ticker =:= &GOOG& andalso Price & 500 -&
Pid ! {sell, 9000, &GOOG&}; % place order with broker
erlang:display(&no rule applied&)
这个版本的to_function取得业务逻辑的抽象形式之后,会返回一个匿名函数(与前一个版本的to_function一样)。在匿名函数里,股票代码、价格条件、broker进程ID这三个变量被从执行作用域中抓出来,经由内建函数erl_eval:add_binding动态绑定到构建出来的表达式中。最后由内建的erl_eval:exprs库函数执行构建好的表达式。
应用业务规则
现在我们加载了业务规则,也为每条规则构造好了Erlang函数,是时候把市场数据参数传给它们了。市场数据用一个元组列表来表示。每个元组代表一对股票代码和股价。
4& MarketData = [{'GOOG', 498}, {'MSFT', 30}, {'AAPL', 158}].
5& dsl:apply_biz_rules(Functions, MarketData).
把函数形式的业务规则,以及市场数据交给apply_biz_rules函数。
apply_biz_rules(Functions, MarketData) -&
lists:map(fun({Ticker,Price}) -&
lists:map(fun(Function) -&
Function(Ticker, Price)
end, Functions)
end, MarketData).
幸亏我们只有三条业务规则,因为apply_biz_rules的运行时是指数增长的。不熟悉Erlang语法或者不留心听讲的话,上面的算法读起来有点难懂。apply_biz_rules函数将一个内部函数映射到市场数据中的每一对股票代码/股价。内部函数又将第二个内部函数映射到每一个业务规则函数。第二个内部函数再将股票代码和股价传递给业务规则函数!
执行apply_biz_rules,broker进程确认它收到买入9000股Google和7000股Apple的指令。
5& dsl:apply_biz_rules(Functions, MarketData).
Order placed: buying 9000 shares of 'GOOG'
Order placed: buying 7000 shares of 'AAPL'
执行结果中没有买入或卖出Microsoft的股票。回头检查一下业务规则,对比一下市场数据可以确定程序的行为是正确的。
buy 9000 shares of GOOG when price is less than 500
sell 400 shares of MSFT when price is greater than 30
buy 7000 shares of AAPL when price is less than 160
4& MarketData = [{'GOOG', 498}, {'MSFT', 30}, {'AAPL', 158}].
如果Google的股价涨了7块,同时我们改变了卖出Microsoft的条件,那么将会观察到不同的结果。
sell 400 shares of MSFT when price is greater than 27
6& UpdatedFunctions = dsl:load_biz_rules(Pid, &new_biz_rules.txt&).
7& UpdatedMarketData = [{'GOOG', 505}, {'MSFT', 30}, {'AAPL', 158}].
8& dsl:apply_biz_rules(UpdatedFunctions, UpdatedMarketData).
Order placed: selling 400 shares of 'MSFT'
Order placed: buying 7000 shares of 'AAPL'
再重申一下我在文章开头所说的观点&&Erlang是构建DSL的极佳平台。其优点远远不止匿名函数、正则表达式支持、模式匹配这几样。Erlang还允许我们编程访问经过词法分析(tokenized)、语法分析之后、抽象形式的表达式。Debasish Ghosh写的《》是另一个很好的例证。我希望本文能帮助一些读者走出自己熟悉的安乐窝,了解一点新的语法和编程范型。我还希望人们在给Erlang贴上专家语言的标签之前能够三思。
就职于,一家全球性的咨询公司,专注于关键系统的全程敏捷软件开发。Dennis是开源社区的活跃分子,他于2008年6月为作了题为&Using Jinterface to bridge Erlang and Java&的演讲。
查看英文原文:。
志愿参与InfoQ中文站内容建设,请邮件至。也欢迎大家到参与我们的线上讨论。
Author Contacted
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
很有lisp的味道
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
通过个性化定制的新闻邮件、RSS Feeds和InfoQ业界邮件通知,保持您对感兴趣的社区内容的时刻关注。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。& erlang和其他语言读文件性能大比拼
erlang和其他语言读文件性能大比拼
原创文章,转载请注明: 转载自
本文链接地址:
百岁同学说:
今天公司技术比武,比赛题目是给一个1.1g的大文本,统计文本中词频最高的前十个词。花了两天用erlang写完了代码,但是放到公司16核的机器上这么一跑,结果不比不知道,一比吓一条。erlang写的代码执行时间花了55秒左右,同事们有的用java,有的用C,还有的用C++,用C最快一个老兄只花了2.6秒,用java的也只用了3.2秒。相比之下erlang的代码,真是一头大蜗牛,太慢了。
详细参见这篇文章:
读取文件并且分析这是很多脚本语言如perl, python,ruby经常会干的事情.这个同学的问题是很普遍的问题,不只一个人反映过慢的问题。
今天我们来重新来修正下这个看法, 我们用数据说话。
首先我们来准备下文件, 这个文件是完全的随机数,有1G大小:
$ dd if=/dev/urandom
of=test.dat count=1024 bs=1024K
1024+0 records in
1024+0 records out
bytes (1.1 GB) copied, 188.474 s, 5.7 MB/s
$ time dd if=test.dat of=/dev/null
records in
records out
bytes (1.1 GB) copied, 1.16021 s, 925 MB/s
$ time dd if=test.dat of=/dev/null bs=1024k
1024+0 records in
1024+0 records out
bytes (1.1 GB) copied, 0.264298 s, 4.1 GB/s
我们准备了1G大小左右的文件,由于用的是buffered io, 数据在准备好了后,全部缓存在pagecache里面,只要内存足够,这个测试的性能和IO设备无关。 我们试着用dd读取这个文件,如果块大小是4K的话,读取这个文件花了1.16秒,而如果块大小是1M的话,0.26秒,带宽达到4.1GB每秒,远超过真实设备的速度。
那么我们用erlang来读取下这个文件来比较下,我们有三种读法:
1. 一下子读取整个1G文件。
2. 一个线程一次读取1块,比如1M大小,直到读完。
3. 多个线程读取,每个读取一大段,每次读取1M块大小。
然后比较下性能。
首先普及下背景:
1. erlang的文件IO操作由efile driver来提高,这个driver内部有个线程池,大小由+A 参数控制,所以IO是多线程完成的。
2. erlang的文件分二种模式: 1. raw模式 2. io模式 在raw模式下,数据直接由driver提供给调用进程, io模式下数据先经过file_server做格式化,然后再给调用进程。
3. 数据可以以binary和list方式返回,list方式下文件内容的byte就是一个整数,在64位机器上占用8个字节内存。
我们编写程序的时候要注意上面几点:
$ cat &rf.erl
-module(rf).
-compile(export_all).
-include_lib(&kernel/include/file.hrl&).
read(Filename)-& read(Filename, 1024 * 1024).
read(File, Bs)-&
case file:open(File, [raw, binary]) of
{ok, Fd} -&
scan_file(Fd, file:read(Fd, Bs), Bs);
{error, _} = E -&
scan_file(Fd, {ok, _Binary}, Bs) -&
scan_file(Fd, file:read(Fd, Bs), Bs);
scan_file(Fd, eof, _Bs) -&
file:close(Fd);
scan_file(Fd, {error, _}, _Bs) -&
file:close(Fd).
read1(Filename) -&
{ok, _Binary} = file:read_file(Filename),
upmap(F, L) -&
Parent = self(),
Ref = make_ref(),
[receive {Ref, Result} -& Result end
|| _ &- [spawn(fun() -& Parent ! {Ref, F(X)} end) || X &- L]].
read2(Filename)-&
PoolSize = erlang:system_info(thread_pool_size),
read2(Filename, PoolSize).
read2(_, 0)-&
io:format(&setting +A first&);
read2(Filename, PoolSize)-&
{ok, FInfo} = file:read_file_info(Filename),
Bs = FInfo#file_info.size div PoolSize,
erlang:display([{bs, Bs}, {poolsize, PoolSize}]),
upmap(fun (Off)-&
{ok, Fd} = file:open(Filename, [raw, binary]),
{ok, _} = file:pread(Fd, Off * Bs, Bs),
file:close(Fd),
erlang:display([reading, block, Off * Bs, Bs, done]),
end, lists:seq(0, PoolSize - 1)),
$ erlc rf.erl
我们导出了三个读,分别对应着上面的3种方式,代码read,read1由帖子的作者的代码稍微修改来的,read2是我自己写的。
我们来测试下文件读取具体的性能:
$ erl +A 16
Erlang R15B03 (erts-5.9.3.1)
[64-bit] [smp:16:16] [async-threads:16] [hipe] [kernel-poll:false]
Eshell V5.9.3.1
(abort with ^G)
1& timer:tc(rf, read, [&test.dat&]).
{322366,ok}
2& timer:tc(rf, read1, [&test.dat&]).
{779240,ok}
3& timer:tc(rf, read2, [&test.dat&]).
[{bs,},{poolsize,16}]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,0,,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,,,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,08864,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,108864,done]
[reading,block,108864,done]
{214904,ok}
4& timer:tc(rf, read, [&test.dat&, 1024]).
5& timer:tc(rf, read, [&test.dat&, 4096]).
{3563313,ok}
我们采用的块大小是1M, 三种模式下对应的读取时间分别是0.322, 0.779, 0.214s,相比dd的0.264s, 我们可以看到多线程模式比c还快,单线程一次读和c差不多。带宽达到4-5G,是理论值的极限,也证明我们把这个事情做到极致了。
同时我们也看到了,如果1次读1K的话,就悲剧了,19秒,很多人会犯的错误。
同样的以4K块读,dd花了1.16秒,而Erlang花了3.56秒, 读完文件循环的次数是1G/4K=25万次。 任何细小的差别放大25万次都会很明显。
结论是: erlang的io是薄薄的一层c封装,每个file:read或者pread的时候,会把读写的具体参数发给driver, 然后等待driver发消息,返回IO结果。 每个io操作会涉及: 发消息+driver做IO操作+等消息 三个阶段。 所以如果我们的io操作太小,发消息和等消息的代价就会大,违反erlang的&#8221;小消息,大计算&#8221;的设计理念,低性能是一定的。
每个语言都有自己的特点,erlang同样有自己的惯用法。在io上,erlang性能是很高的,那么多的数据库系统是erlang写的也是佐证。
祝玩得开心!
Post Footer automatically generated by
for wordpress.
Related posts:
Categories: , ,
No trackbacks yet.
buy me a coffee.
阿里核心系统数据库组招募高手!
招聘信息:
Recent Posts英['?:lae?]
美['?:lae?]
厄兰(话务单位)
1.a unit of traffic intensity in a telephone system
只有登录后,才能查看此项,现在是否?
好文推荐:}

我要回帖

更多关于 erlang 读写文件 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信