`
mryufeng
  • 浏览: 982346 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

变量不是不可变

阅读更多
erlang的变量是不可变的 这是语法层面的事情,照理是绕不过的。但是hipe,erlang的jit模块打开了这扇门,请看:

sf bay facory 来自Facebook的Eugene Letuchy在ppt
http://www.erlang-factory.com/upload/presentations/31/EugeneLetuchy-ErlangatFacebook.pdf 里面提到:

hipe_bifs
Cheating single assignment
▪ Erlang is opinionated:
▪ Destructive assignment is hard because it should be
▪ hipe_bifs:bytearray_update() allows for destructive array assignment
▪ Necessary for aggregating Chat users’ presence
▪ Don’t tell anyone!

这是一个很好的绕过变量不可变的方法, 我再挖掘下google, 发现如下的文章:
http://erlang.org/pipermail/erlang-questions/2007-February/025331.html
Per Gustafsson <>
Thu Feb 22 17:41:01 CET 2007

    * Previous message: [erlang-questions] Deforesting tuple updates
    * Next message: [erlang-questions] Is UBF still going, or did it morph/fade?
    * Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

Joel Reymont wrote:
> I don't think it works for floats or doubles. It's just bytes or 
> fixnums if I remember it correctly.
>
> On Feb 22, 2007, at 3:32 PM, Daniel Luna wrote:
>
>
>>As long as the values in the array are simple terms, you can use 
>>hipe_bifs:bytearray/2.
>
>
> --
> http://wagerlabs.com/
>
>
>
>
>
> _______________________________________________
> erlang-questions mailing list
>
> http://www.erlang.org/mailman/listinfo/erlang-questions

You could use this code:

-module(floats).

-export([new/1,update/3,sum/1,
new2/1,update2/3,sum2/1,
test/0]).

new(N) ->
   hipe_bifs:bytearray(N*8,0).

update(Arr,N,Float) ->
   <<A1,A2,A3,A4,A5,A6,A7,A8>> = <<Float/float>>,
   Start=N*8,
   hipe_bifs:bytearray_update(Arr,Start,A1),
   hipe_bifs:bytearray_update(Arr,Start+1,A2),
   hipe_bifs:bytearray_update(Arr,Start+2,A3),
   hipe_bifs:bytearray_update(Arr,Start+3,A4),
   hipe_bifs:bytearray_update(Arr,Start+4,A5),
   hipe_bifs:bytearray_update(Arr,Start+5,A6),
   hipe_bifs:bytearray_update(Arr,Start+6,A7),
   hipe_bifs:bytearray_update(Arr,Start+7,A8).

sum(Bin) ->
   sum(Bin,0.0).

sum(<<Float/float,Rest/binary>>, Acc) ->
   sum(Rest,Float+Acc);
sum(<<>>,Acc) -> Acc.

Performance is not that great, about 4-5 times faster updates than
gb_trees for arrays of 100000 floats, and summing is slower.

Per

试验下:
root@yufeng-desktop:~# cat floats.erl
-module(floats).

-export([new/1,update/3,sum/1]).

new(N) ->
   hipe_bifs:bytearray(N*8,0).

update(Arr,N,Float) ->
   <<A1,A2,A3,A4,A5,A6,A7,A8>> = <<Float/float>>,
   Start=N*8,
   hipe_bifs:bytearray_update(Arr,Start,A1),
   hipe_bifs:bytearray_update(Arr,Start+1,A2),
   hipe_bifs:bytearray_update(Arr,Start+2,A3),
   hipe_bifs:bytearray_update(Arr,Start+3,A4),
   hipe_bifs:bytearray_update(Arr,Start+4,A5),
   hipe_bifs:bytearray_update(Arr,Start+5,A6),
   hipe_bifs:bytearray_update(Arr,Start+6,A7),
   hipe_bifs:bytearray_update(Arr,Start+7,A8).

sum(Bin) ->
   sum(Bin,0.0).

sum(<<Float/float,Rest/binary>>, Acc) ->
   sum(Rest,Float+Acc);
sum(<<>>,Acc) -> Acc.


root@yufeng-desktop:~# erl
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1>  F = floats:new(5).
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,...>>
2> rp(F).
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0>>
ok
3> floats:update(F, 1, 1234.00).
<<0,0,0,0,0,0,0,0,64,147,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,...>>
4> rp(F).                      
<<0,0,0,0,0,0,0,0,64,147,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
ok
5> floats:update(F, 2, 5678.00).
<<0,0,0,0,0,0,0,0,64,147,72,0,0,0,0,0,64,182,46,0,0,0,0,0,
  0,0,0,0,0,...>>
6> rp(F).                      
<<0,0,0,0,0,0,0,0,64,147,72,0,0,0,0,0,64,182,46,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
ok
7> floats:sum(F).
6912.0
8> 1234+ 5678=6912.
6912
9>

恩 没问题的, 不错。
再到源码去挖掘下
...\otp_src_R13A-0\erts\emulator\hipe\hipe_bif0.tab

bif hipe_bifs:bytearray/2
bif hipe_bifs:bytearray_sub/2
bif hipe_bifs:bytearray_update/3
bif hipe_bifs:bitarray/2
bif hipe_bifs:bitarray_sub/2
bif hipe_bifs:bitarray_update/3
bif hipe_bifs:array/2
bif hipe_bifs:array_length/1
bif hipe_bifs:array_sub/2
bif hipe_bifs:array_update/3

bif hipe_bifs:ref/1
bif hipe_bifs:ref_get/1
bif hipe_bifs:ref_set/2

root@yufeng-desktop:~# erl
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
1>  A=hipe_bifs:array(10, []).
2135987033931617136292706780490918553627426255794015745390464377869606912860751039403868490301435
2> rp(A).                    
2135987033931617136292706780490918553627426255794015745390464377869606912860751039403868490301435
ok
3> hipe_bifs:array_length(A).
10
4> hipe_bifs:array_update(A, 2, 1). 
2135987033931617136292706780490918553627426255794015745390464377869527684698900857852928490209275
5> 
5> hipe_bifs:array_update(A, 1, atom). 
2135987033931617136292706780490918553627426255794015745390464377869527684698882411121018128039931
6> hipe_bifs:array_sub(A,1).                 
atom
7> hipe_bifs:array_sub(A,2).
1
8> R=hipe_bifs:ref(1).
31
9> hipe_bifs:ref_get(R).
1
10> hipe_bifs:ref_set(R, 10).
175
11> hipe_bifs:ref_get(R). 
10

O Yeah 这些也都OK.

还有很多hipe_bifs的导出在相应的.tab文件里面,读者自己挖掘了。这样我们就可以把状态更新, 无需通过消息 或者 ets, 大大加快效率。



附上8皇后的hipe源码。
分享到:
评论
11 楼 mryufeng 2009-11-11  
whrllm 写道
呵呵,你来我这,我包你吃饭喝酒泡妞//

这还差不多 多教你点
10 楼 whrllm 2009-11-11  
呵呵,你来我这,我包你吃饭喝酒泡妞//
9 楼 whrllm 2009-11-11  
老大,请问一下,如何结合const pool使用啊?能不能提示一下啊?谢谢
8 楼 mryufeng 2009-11-11  
whrllm 写道
以前没能理解,现在用上了,才知道好啊,老大,你的好东西太多了,哈哈/

请吃饭喝酒泡妞吧
7 楼 whrllm 2009-11-11  
以前没能理解,现在用上了,才知道好啊,老大,你的好东西太多了,哈哈/
6 楼 mryufeng 2009-06-03  
主要是考虑到erlang的所以状态都是在进程维护的 要改变状态 必须给进程发消息  这个开销有时候是不可承受的 比较改变一个变量的值 要做的事情太多  进程要调度2次 很吓人的。
5 楼 halida 2009-06-03  
原先優美簡單的程序就是這樣一步步被crack成為復雜,難以理解,難以維護的遺產代碼的。。。
4 楼 mryufeng 2009-05-31  
结合const pool我们可以做出全局变量的东西 哈哈 真好用!
3 楼 mryufeng 2009-05-31  
en 这个是追求速度 某些场合还是很好用的
2 楼 美洲豹 2009-05-30  
估计这些都是所谓的脏函数
1 楼 mryufeng 2009-05-30  
不过除非必要 不要用这些trick 毕竟是和设计的初衷违背的东西。

相关推荐

Global site tag (gtag.js) - Google Analytics