<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

        今天費了一個下午安裝了redhat9,并且安裝了需要使用的jdk5、netbean、ruby和Erlang。做個備忘。

    一。安裝jdk5
    1.到sun的網站上下載jdk5與netbean5.5的捆綁版本,注意要linux平臺的

    2.比如下載到/root/目錄下,執行
    chmod 755 jdk-1_5_0_12-nb-5_5_1-linux-ml.bin
    然后執行:
    ./jdk-1_5_0_12-nb-5_5_1-linux-ml.bin
    就會自動啟動安裝向導,一路選擇確定下去就OK了。

    3.設置環境變量,這時其實沒有設置就可以啟動netbean了,不過為了在終端執行,還是要設置下環境變量,使用vi編輯/etc/profile配置文件,在最后面加上:
    JAVA_HOME=/opt/jdk1.5.0_12
    PATH
    =/opt/jdk1.5.0_12/bin:$PATH
    CLASSPATH
    =/opt/jdk1.5.0_12/lib/dt.jar:/opt/jdk1.5.0_12/lib/tools.jar
    export JAVA_HOME PATH CLASSPATH
    保存退出,reboot下就OK

    二。安裝ruby
    1.到ruby-lang.org下載ruby-1.8.6.tar.gz
    2.解壓縮并進入解壓后的目錄:
    tar xzvf ruby-1.8.6.tar.gz
    cd ruby-1.8.6

    3.默認是安裝/usr/local目錄下,可以通過下面的命令設置安裝到/usr/local/ruby目錄下:
    /.configure -prefix=/usr/local/ruby

    4.執行命令:make && make install

    5.再次編輯vi /etc/profile,修改我們在上面提到的PATH,把ruby的bin加進去:
    PATH=/usr/local/ruby/bin:/opt/jdk1.5.0_12/bin:$PATH

    6.測試下是否正確安裝,
    ruby -version
    ruby -e "puts 'hello'"

    三、Erlang的安裝

    1.到Erlang.org下載最新版本的linux平臺下的Erlang(源代碼版本,需要自己編譯),比如otp_src_R11B-5.tar.gz

    2.解壓縮,并進入解壓后的目錄:
    tar zxvf otp_src_R11B-5.tar.gz
    cd otp_src_R11B-5

    3.build Erlang需要下列工具,確認你的linux版本有安裝:
     GNU make

     GNU C compiler

     Perl 5

     OpenSSL

     Sun Java jdk-1.2.2

     X Windows

     sed  solaris平臺需要

     Flex 可選

    4.安裝過程,順序執行下列命令,包括OTP在內都將被安裝
    1)export LANG=#如果是C Shell,執行setenv LANG C,linux一般是Bourne shell



    2)./configure

    3)make

    4)make install

    5.確認安裝正確,新開一個終端,執行erl進入Erlang shell

    最后啟動下ssh,允許防火墻通過ssh執行下面的命令,在windows上搞個putty
    iptables -A INPUT -p tcp --sport 22 -j ACCEPT
    iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT




    posted @ 2007-06-28 18:08 dennis 閱讀(1012) | 評論 (0)編輯 收藏

    這一節的內容非常有趣,通過將序列作為interface,在此基礎上進而提取出各種高階操作(map,filter,accumulate,enumerate等),由此引出模塊化設計的討論。模塊化設計帶來復雜性的降低,同時可能引入性能上的損失,比如書中對sum-odd-squares過程的兩種寫法,原來的寫法枚舉列表元素的過程散落在累積、過濾、映射的過程中,主要一次循環就夠了,而通過三個高階過程來操作反而需要3次的遍歷。

    習題2.33,將map,append,length基本過程用累積操作重新定義,聯系以往的實現通過觀察和測試可以得出:
    (define (map p sequence)
      (accumulate  (
    lambda(x y) 
                    (cons (p x) y))       
                           () sequence))
    (define (append seq1 seq2)
      (accumulate cons seq2 seq1))
    (define (length sequence)
      (accumulate (
    lambda(x y)
                    (
    + 1 y))
                    0 sequence))
    難點就在于累積的操作。

    習題2.34,Horner規則求多項式,難點也是累積操作的定義:
    (define (horner-eval x coefficient-sequence)
      (accumulate (
    lambda(this-coeff higher-terms)
                    (
    + this-coeff (* x higher-terms)))
                  0 coefficient
    -sequence))
    只要記住lambda中的y其實是另一個遞歸的accumulate就比較容易完成了。
    測試下:
    > (horner-eval 2 (list 1 3 0 5 0 1))
     
    79

    習題2.35,利用map和accumulate重新定義count-leaves統計樹的節點數目:
    (define (count-leaves t)
      (accumulate 
    + 0 (map (lambda (x) (if (pair? x) (count-leaves x) 1)) t)))
    map過程的參數op是過程
    (lambda (x) (if (pair? x) (count-leaves x) 1))
    當x是列表,遞歸調用count-leaves,否則返回個數1

    習題2.36,列表的列表,因此map過程的第一個參數是一個過程作用于列表中的每個列表,當然是采用car將它們首項取出然后進行op操作,因此:
    (define (accumulate-n op init seqs)
      (
    if (null? (car seqs))
          ()
          (cons (accumulate op init (map car seqs))
                (accumulate
    -n op init (map cdr seqs)))))

    習題2.37,list作為Lisp的基本結構可以演化出各式各樣的復雜結構,比如此題就將列表作為矢量,矢量通過組合成為矩陣,3個解答就是矩陣的運算:
    (define (dot-product v w)
      (accumulate 
    + 0 (map * v w)))
    (define (matrix
    -*-vector m v)
      (map (
    lambda (x) (dot-product x v)) m))
    (define (transpose mat)
      (accumulate
    -n cons () mat))
    (define (matrix
    -*-matrix m n)
      (let ((cols (transpose n)))
        (map (
    lambda (x) (matrix-*-vector cols x)) m)))
    知道矩陣運算的定義得出結果并不困難。

    習題2.38,計算下結果:
    > (fold-right / 1 (list 1 2 3))
    1 1/2
    ;也就是3
    /2

    > (fold-left / 1 (list 1 2 3))
    1/6
    > (fold-right list () (list 1 2 3))
    (
    1 (2 (3 ())))
    > (fold-left list () (list 1 2 3))
    (((() 
    123)

    如果想使這兩個過程的結果相同,op需要滿足交換率和結合率的條件。

    習題2.39:
    ;2.39
    (define (reverse
    -list sequence)
      (fold
    -right (lambda(x y)(append y (list x))) () sequence))
    (define (reverse
    -list2 sequence)
      (fold
    -left (lambda(x y) (cons y x)) () sequence))




    posted @ 2007-06-27 15:14 dennis 閱讀(496) | 評論 (3)編輯 收藏

        這個類在spring2.01前沒有被改寫,spring2.06似乎已經改寫了,還未看源碼。不過這不是我所在意的問題。我在《org.springframework.beans簡單解讀》中的對這個類的理解是不正確的。我們先看看Guillaume Poirier對這個類中為什么使用WeakHashMap的解釋:

    WeakHashMap is implemented with WeakReference for keys, and strong reference for values. That means if the value has a strong reference on the key, then the key cannot be garbage collected until the WeakHashMap is ready for collection. However, if the value has no strong reference on its key, then being in the WeakHashMap won't prevent the key and value from being garbage collected if it is otherwise ready. The WeakHashMap knows when to remove the key (and the value with it) by using the notification provided by the java.lang.ref package. For more information on this, see: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ref/package-summary.html

    So the problem here with the CachedIntrospectionResults is that it uses BeanInfo and PropertyDescriptor that both have strong reference to the class (indirectly by a reference on Methods of the class). That will be solved with JDK 1.5 that uses a combinaison of Weak and Soft Reference to the Class and Method objects, but for 1.4.2, there's not really any better solution than to flush the Introspector's cache and/or use WeakReference on CachedIntrospectionResults. Using WeakReference on the CachedIntrospectionResults is safer, but decrease performance, and in such case a manual Instrospector.flushFromCaches(Class) must be used, so that the Instrospector does not keep a strong reference on the BeanInfo.

    When a webapp is hot-redeployed, a new ClassLoader is created to load the webapp, and the old one is thrown away, expected to be garbage collected. For the collection to happen, the server must clear any strong reference to the ClassLoader or its classes, and also the webapp must make sure that any code in parent ClassLoaders (or siblings) clear any reference it might have to any of the webapp's class.

        照他的說法和參考《深入JVM》一書,對Class有強引用的有:ClassLoader,java.beans.BeanInfo,java.beans.PropertyDescriptor,java.lang.reflect.Method。因為在這個緩存中使用Class作為key,而Value是CachedIntrospectionResults,CachedIntrospectionResults中持有BeanInfo和Method的引用,這兩個都對Class對象有強引用(這一點據說在jdk5中已經修改,被改成軟引用和弱引用的組合,而在jdk1.4.2需要這樣的處理),導致在web應用關閉或者熱部署的時候,舊的ClassLoader和它引用的類不能被回收,因此使用弱引用包裝CachedIntrospectionResults對象作為Value。web應用關閉或者熱部署的時候,會new新的ClassLoader用于裝載類,這就是CachedIntrospectionResults判斷緩存是否safe的根據所在,判斷要緩存的Class引用的ClassLoader是否相同。
        當使用JavaBean的內省時,使用Introspector,jdk會自動緩存內省的信息(BeanInfo),這一點可以理解,因為內省通過反射的代價是高昂的。當ClassLoader關閉的時候,Introspector的緩存持有BeanInfo的信息,而BeanInfo持有Class的強引用,這將導致ClassLoader和它引用的Class等對象不能被垃圾收集器回收,因此在關閉前,需要手工清除Introspector中的緩存,調用Introspector.flushFromCaches,這就是CachedIntrospectionResults中當得到BeanInfo后為什么要執行下面這段代碼的原因:
                this.beanInfo = Introspector.getBeanInfo(clazz);

                
    // Immediately remove class from Introspector cache, to allow for proper
                
    // garbage collection on class loader shutdown - we cache it here anyway,
                
    // in a GC-friendly manner. In contrast to CachedIntrospectionResults,
                
    // Introspector does not use WeakReferences as values of its WeakHashMap!
                Class classToFlush = clazz;
                
    do {
                    Introspector.flushFromCaches(classToFlush);
                    classToFlush 
    = classToFlush.getSuperclass();
                }
                
    while (classToFlush != null);

    說到這里,spring中有一個比較少人注意的Listener——org.springframework.web.util.IntrospectorCleanupListener,這個類的說明如下:

    它是一個在web應用關閉的時候,清除JavaBeans Introspector緩存的監聽器.在web.xml中注冊這個listener.可以保證在web 應用關閉的時候釋放與掉這個web 應用相關的class loader 和由它加載的類
     
    如果你使用了JavaBeans Introspector來分析應用中的類,系統級Introspector 緩沖中會保留這些類的hard引用。結果在你的web應用關閉的時候,這些類以及web 應用相關的class loader沒有被垃圾收集器回收.
     
    不幸的是,清除Introspector的唯一方式是刷新整個緩存。這是因為我們沒法判斷哪些是屬于你的應用的引用.所以刪除被緩沖的introspection會導致把這臺server上的所有應用的introspection(內省)結果都刪掉.
     
    需要注意的是,spring容器托管的bean不需要使用這個監聽器.因為spring它自己的introspection所使用的緩沖在分析完一個類之后會被馬上從javaBeans Introspector緩沖中清除掉(上面提到的代碼說明了這一點)

    一般的應用基本不會直接用到JavaBean的內省方法,所以一般不用考慮遇到此類內省資源泄露,但是,很多的類庫或者框架(比如struts,Quartz)沒有清除Introspector。這個Listener就是為它們“擦屁股”的。請注意,這個監聽器需要注冊在web.xml中的所有應用監聽器之前(比如ContentLoaderListener之前)
    <listener>
       
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

        參考資料:
     《深入Java虛擬機》
     《Class對象什么時候被回收?
     《Spring API Doc
      《ss目前的設計有引起內存泄露而導致down機的隱患
     以及一篇非常好的解釋java引用類的文章《Java對象的強、軟、弱和虛引用




    posted @ 2007-06-26 10:39 dennis 閱讀(3013) | 評論 (1)編輯 收藏

         摘要:     去了趟福州,事情沒搞定,托給同學幫忙處理了,回家休息了兩天就來上班了。回家這幾天最大的收獲是第四次重讀《深入Java虛擬機》,以前不大明了的章節豁然開朗,有種開竅的感覺,水到渠成,看來技術的學習還是急不來。    閑話不提,繼續Erlang的學習,上次學習到分布式編程的章節,剩下三章分別是錯誤處理、構造健壯的系統和雜項,錯誤處理和...  閱讀全文

    posted @ 2007-06-25 17:10 dennis 閱讀(6114) | 評論 (0)編輯 收藏

        明天要回家一個星期了,好好休息下。今天找到別人翻譯的Erlang編程手冊,值的好好讀一遍。
        所謂分布式的Erlang應用是運行在一系列Erlang節點組成的網絡之上。這樣的系統的性質與單一節點上的Erlang系統并沒有什么不同。分布式這是個“大詞”,Erlang從語言原生角度支持分布式編程,相比于java簡單不少。
    一、分布式機制
    下列的BIFs是用于分布式編程:
    spawn(Node, Mod, Func, Args)
    啟動遠程節點的一個進程

    spawn_link(Node, Mod, Func, Args)
    啟動遠程節點的一個進程并創建連接到該進程

    monitor_node(Node, Flag)
    如果Flag是true,這個函數將使調用(該函數)的進程可以監控節點Node。如果節點已經舍棄或者并不存在,調用的進程將收到一個{nodedown,Node}的消息。如果Flag是false,監控將被關閉

    node()
    返回我們自己的進程name

    nodes()
    返回其他已知的節點name列表

    node(Item)
    返回原來Item的節點名稱,Item可以是Pid,引用(reference)或者端口(port)

    disconnect_node(Nodename)
    從節點Nodename斷開。

        節點是分布式Erlang的核心概念。在一個分布式Erlang應用中,術語(term)節點(node)意味著一個可以加入分布式transactions的運行系統。通過一個稱為net kernal的特殊進程,一個獨立的Erlang系統可以成為一個分布式Erlang系統的一部分。當net kernal進程啟動的時候,我們稱系統是alive的。

        與遠程節點上的進程進行通信,與同一節點內的進程通信只有一點不同:
      
       {Name, Node} ! Mess.
    顯然,需要接收方增加一個參數Node用于指定接受進程所在的節點。節點的name一般是用@隔開的atom類型,比如pong@dennis,表示計算機名為dennis上的pong節點。通過執行:
    erl -sname pong
    將在執行的計算機中創建一個節點pong。為了運行下面的例子,你可能需要兩臺計算機,如果只有一臺,只要同時開兩個Erlang系統并以不同的節點名稱運行也可以。

    二、一些例子。
        這個例子完全來自上面提到的翻譯的連接,關于分布式編程的章節。我增加了截圖和說明。
    首先是代碼:
    -module(tut17).

    -export([start_ping/1, start_pong/0,  ping/2, pong/0]).

    ping(
    0, Pong_Node) ->
        {pong
    , Pong_Node} ! finished,
        io
    :format("ping finished~n", []);

    ping(N
    , Pong_Node) ->
        {pong
    , Pong_Node} ! {ping, self()},
        receive
            pong 
    ->
                io
    :format("Ping received pong~n", [])
        end
    ,
        ping(N 
    - 1, Pong_Node).

    pong() 
    ->
        receive
            finished 
    ->
                io
    :format("Pong finished~n", []);
            {ping
    , Ping_PID} ->
                io
    :format("Pong received ping~n", []),
                Ping_PID 
    ! pong,
                pong()
        end
    .

    start_pong() 
    ->
        register(pong
    , spawn(tut17, pong, [])).

    start_ping(Pong_Node) 
    ->
        spawn(tut17
    , ping, [3, Pong_Node]).

        代碼是創建兩個相互通信的進程,相互發送消息并通過io顯示在屏幕上,本來是一個單一系統的例子,現在我們讓兩個進程運行在不同的兩個節點上。注意start_ping方法,創建的進程調用ping方法,ping方法有兩個參數,一個是發送消息的次數,一個就是遠程節點的name了,也就是我們將要創建的進程pong的所在節點。start_pong創建一個調用函數pong的進程,并注冊為名字pong(因此在ping方法中可以直接發送消息給pong)。
        我是在windows機器上測試,首先打開兩個cmd窗口,并cd到Erlang的安裝目錄下的bin目錄,比如C:\Program Files\erl5.5.3\bin,將上面的程序存為tut17.erl,并拷貝到同一個目錄下。我們將創建兩個節點,一個叫ping@dennis,一個叫pong@dennis,其中dennis是我的機器名。見下圖:

    采用同樣的命令
    erl -sname ping
    創建ping節點。然后在pong節點下執行start_pong():


    OK,這樣就在節點pong上啟動了pong進程,然后在ping節點調用start_ping,傳入參數就是pong@dennis
    tut17:start_ping(pong@dennis).
    執行結果如下圖:

    同樣在pong節點上也可以看到:


        結果如我們預期的那樣,不同節點上的兩個進程相互通信如此簡單。我們給模塊tut17增加一個方法,用于啟動遠程進程,也就是調用spawn(Node,Module,Func,Args)方法:
    start(Ping_Node) ->
        register(pong
    , spawn(tut17, pong, [])),
        spawn(Ping_Node
    , tut17, ping, [3, node()]).
    pong進程啟動Ping_Node節點上的進程ping。具體結果不再給出。



        

    posted @ 2007-06-15 17:33 dennis 閱讀(5513) | 評論 (1)編輯 收藏

        Erlang中的process——進程是輕量級的,并且進程間無共享。查了很多資料,似乎沒人說清楚輕量級進程算是什么概念,繼續查找中。。。閑話不提,進入并發編程的世界。本文算是學習筆記,也可以說是《Concurrent Programming in ERLANG》第五張的簡略翻譯。
    1.進程的創建
        進程是一種自包含的、分隔的計算單元,并與其他進程并發運行在系統中,在進程間并沒有一個繼承體系,當然,應用開發者可以設計這樣一個繼承體系。
        進程的創建使用如下語法:
    Pid = spawn(Module, FunctionName, ArgumentList)

    spawn接受三個參數:模塊名,函數名以及參數列表,并返回一個代表創建的進程的標識符(Pid)。
    如果在一個已知進程Pid1中執行:
    Pid2 = spawn(Mod, Func, Args)
    那么,Pid2僅僅能被Pid1可見,Erlang系統的安全性就構建在限制進程擴展的基礎上。

    2.進程間通信
        Erlang進程間的通信只能通過發送消息來實現,消息的發送使用!符號:
    Pid ! Message
        其中Pid是接受消息的進程標記符,Message就是消息。接受方和消息可以是任何的有效的Erlang結構,只要他們的結果返回的是進程標記符和消息。
        消息的接受是使用receive關鍵字,語法如下:
    receive
          Message1 [when Guard1] 
    ->
              Actions1 ;
          Message2 [when Guard2] 
    ->
              Actions2 ;

    end

        每一個Erlang進程都有一個“郵箱”,所有發送到進程的消息都按照到達的順序存儲在“郵箱”里,上面所示的消息Message1,Message2,當它們與“郵箱”里的消息匹配,并且約束(Guard)通過,那么相應的ActionN將執行,并且receive返回的是ActionN的最后一條執行語句的結果。Erlang對“郵箱”里的消息匹配是有選擇性的,只有匹配的消息將被觸發相應的Action,而沒有匹配的消息將仍然保留在“郵箱”里。這一機制保證了沒有消息會阻塞其他消息的到達。
        消息到達的順序并不決定消息的優先級,進程將輪流檢查“郵箱”里的消息進行嘗試匹配。消息的優先級別下文再講。

        如何接受特定進程的消息呢?答案很簡單,將發送方(sender)也附送在消息當中,接收方通過模式匹配決定是否接受,比如:
    Pid ! {self(),abc}
    給進程Pid發送消息{self(),abc},利用self過程得到發送方作為消息發送。然后接收方:
    receive
      {Pid
    1,Msg} ->

    end
    通過模式匹配決定只有Pid1進程發送的消息才接受。

    3.一些例子
        僅說明下書中計數的進程例子,我添加了簡單注釋:
    -module(counter).
    -compile(export_all).
    % start(),返回一個新進程,進程執行函數loop
    start()
    ->spawn(counter, loop,[0]).
    % 調用此操作遞增計數
    increment(Counter)
    ->
        Counter
    !increament.
    % 返回當前計數值
    value(Counter)
    ->
        Counter
    !{self(),value},
        receive
            {Counter
    ,Value}->
                
    %返回給調用方
                Value
            end
    .
      
    %停止計數      
     stop(Counter)
    ->
         Counter
    !{self(),stop}.
     loop(Val)
    ->
         receive
             
    %接受不同的消息,決定返回結果
             increament
    ->
                 loop(Val
    +1);
             {From
    ,value}->
                 From
    !{self(),Val},
                 loop(Val);
             stop
    ->
                 true;
             
    %不是以上3種消息,就繼續等待
             Other
    ->
                 loop(Val)
          end
    .   
                 
                            
            


    調用方式:
    1> Counter1=counter:start().
    <0.30.0>
    2> counter:value(Counter1).
    0
    3> counter:increment(Counter1).
    increament
    4> counter:value(Counter1).
    1

    基于進程的消息傳遞機制可以很容易地實現有限狀態機(FSM),狀態使用函數表示,而事件就是消息。具體不再展開

    4.超時設置
        Erlang中的receive語法可以添加一個額外選項:timeout,類似:
    receive
       Message1 [when Guard1] 
    ->
         Actions1 ;
       Message2 [when Guard2] 
    ->
         Actions2 ;
       

       after
          TimeOutExpr 
    ->
             ActionsT
    end

    after之后的TimeOutExpr表達式返回一個整數time(毫秒級別),時間的精確程度依賴于Erlang在操作系統或者硬件的實現。如果在time毫秒內,沒有一個消息被選中,超時設置將生效,也就是ActionT將執行。time有兩個特殊值:
    1)infinity(無窮大),infinity是一個atom,指定了超時設置將永遠不會被執行。
    2) 0,超時如果設定為0意味著超時設置將立刻執行,但是系統將首先嘗試當前“郵箱”里的消息。

        超時的常見幾個應用,比如掛起當前進程多少毫秒:
    sleep(Time->
      receive
        after 
    Time ->
        true
    end
    .
        比如清空進程的“郵箱”,丟棄“郵箱”里的所有消息:
       
    flush_buffer() ->
      receive
        AnyMessage 
    ->
          flush_buffer()
      after 
    0 ->
        true
    end
    .
        將當前進程永遠掛起:
      suspend() ->
        receive
        after
            infinity 
    ->
                true
        end
    .
        超時也可以應用于實現定時器,比如下面這個例子,創建一個進程,這個進程將在設定時間后向自己發送消息:
    -module(timer).
    -export([timeout/2,cancel/1,timer/3]).
    timeout(
    Time, Alarm->
       spawn(timer
    , timer, [self(),Time,Alarm]).
    cancel(Timer) 
    ->
       Timer 
    ! {self(),cancel}.
    timer(Pid
    , Time, Alarm->
       receive
        {Pid
    ,cancel} ->
           true
       after 
    Time ->
           Pid 
    ! Alarm
    end
    .

       
    5、注冊進程
        為了給進程發送消息,我們需要知道進程的Pid,但是在某些情況下:在一個很大系統里面有很多的全局servers,或者為了安全考慮需要隱藏進程Pid。為了達到可以發送消息給一個不知道Pid的進程的目的,我們提供了注冊進程的辦法,給進程們注冊名字,這些名字必須是atom。
        基本的調用形式:
    register(Name, Pid)
    將Name與進程Pid聯系起來

    unregister(Name)
    取消Name與相應進程的對應關系。

    whereis(Name)
    返回Name所關聯的進程的Pid,如果沒有進程與之關聯,就返回atom
    :undefined

    registered()
    返回當前注冊的進程的名字列表

    6.進程的優先級
    設定進程的優先級可以使用BIFs:
    process_flag(priority, Pri)

    Pri可以是normal、low,默認都是normal
    優先級高的進程將相對低的執行多一點。

    7.進程組(process group)
        所有的ERLANG進程都有一個Pid與一個他們共有的稱為Group Leader相關聯,當一個新的進程被創建的時候將被加入同一個進程組。最初的系統進程的Group Leader就是它自身,因此它也是所有被創建進程及子進程的Group Leader。這就意味著Erlang的進程被組織為一棵Tree,其中的根節點就是第一個被創建的進程。下面的BIFs被用于操縱進程組:
    group_leader()
    返回執行進程的Group Leader的Pid
    group_leader(Leader, Pid)
    設置進程Pid的Group Leader為進程的Leader

    8.Erlang的進程模型很容易去構建Client-Server的模型,書中有一節專門討論了這一點,著重強調了接口的設計以及抽象層次的隔離問題,不翻譯了。

    posted @ 2007-06-14 17:12 dennis 閱讀(7166) | 評論 (0)編輯 收藏

    Erlang logo

    Erlang前世今生


    1982 - 1985

    我們使用了 > 20種語言進行了電信行業的編程實驗,結論是:這樣的語言需要是一門高度的抽象的語言才能達到生產力目標。(給我們留下印象的有:List,Prolog,Parlog ...)

    1985 - 86

    我們使用Lisp,Prolog,Parlog等語言進行了實驗,結論是:這樣的語言需要原生支持的并發控制和容錯處理,并且執行模型必須沒有使用回溯。(排除了List和Prolog.) 而且它必須擁有并發粒度比如一個異步的電話進程可以用語言的一個進程表示(排除了Parlog)。最后我們不得不開發一門我們自己的語言,它擁有 Lisp,Prolog和Parlog的特性,但內置了并發和容錯處理。

    1987

    第一次使用erlang進行實驗。

    1988

    ACS/Dunder(項目)第一階段:外來用戶使用erlang進行PABX(專用自動交換分機)功能的原型構建, Erlang走出了實驗室!

    1989

     ACS/Dunder(項目)第二階段:重新改造了完整的MD-110系統的1/10,結果:相比于使用PLEX的構建有>>10倍的效率提高!

    1990

     Erlang正式以ISS'90標準發布,這帶來不少的新用戶,比如Bellcore。

    1991

    Erlang發布了更快的版本實現給用戶,Erlang應用于電信'91(項目?),更多功能比如編譯器、圖形接口等。

    1992

     更多的新用戶,許多高速發展的項目。Erlang可以運行于VxWorks,PC,Macintosh等系統。有三個應用使用了ISS'92標準的Erlang。

    1993

     分布式支持加進了Erlang,這使得erlang可以運行一個自發系統在不同的硬件上。決定向外部發布Erlang的實現,從愛立信分離出獨立的部門開始維護和支持Erlang的實現和Erlang工具的開發工作。

    posted @ 2007-06-14 09:28 dennis 閱讀(2146) | 評論 (2)編輯 收藏

        讀erlang.org上面的Erlang Course四天教程
    1.數字類型,需要注意兩點
    1)B#Val表示以B進制存儲的數字Val,比如
    7> 2#101.
    5
    進制存儲的101就是10進制的5了
    2)$Char表示字符Char的ascii編碼,比如$A表示65

    2.比較難以翻譯的概念——atom,可以理解成常量,它可以包含任何字符,以小寫字母開頭,如果不是以小寫字母開頭或者是字母之外的符號,需要用單引號包括起來,比如abc,'AB'

    3.另一個概念——Tuple,有人翻譯成元組,可以理解成定長數組,是Erlang的基礎數據結構之一:
    8> {1,2,3,4,5}.
    {
    1,2,3,4,5}
    9> {a,b,c,1,2}.
    {a
    ,b,c,1,2}
    10> size({1,2,3,a,b,c}).
    6
    內置函數size求長度,元組可以嵌套元組或者其他結構。下面所講的列表也一樣。

    4.另外一個基礎數據結構就是各個語言都有的list(列表),在[]內以,隔開,可以動態改變大小,
        [123, xyz]
        [
    123, def, abc]
        [{person
    , 'Joe', 'Armstrong'},
            {person
    , 'Robert', 'Virding'},
            {person
    , 'Mike', 'Williams'}
        ]
    可以使用內置函數length求列表大小。以""包含的ascii字母代表一個列表,里面的元素就是這些字母的ascii值,比如"abc"表示列表[97,98,99]。

    5.通過這兩個數據結構可以組合成各種復雜結構,與Lisp的cons、list演化出各種結構一樣的奇妙,Erlang也可以當作是操作列表的語言。

    6.Erlang中變量有兩個特點:
    1)變量必須以大寫字母或者下劃線開頭,可以包含字母、下劃線和@
    2)變量只能綁定一次,也就是所謂的Single Assignment。或者以一般的說法就是只能賦值一次,其實Erlang并沒有賦值這樣的概念,=號也是用于驗證匹配。

    7.模式匹配——Pattern Matching,Erlang的模式匹配非常強大,看了buaawhl的《Erlang語法提要》的介紹,模式匹配的功能不僅僅在課程中介紹的數據結構的拆解,在程序的分派也扮演重要角色,或者說Erlang的控制的流轉是通過模式匹配來實現的。具體功能參見鏈接,給出書中拆解列表的例子:
        [A,B|C] = [1,2,3,4,5,6,7]
            Succeeds 
    - binds A = 1, B = 2,
            C 
    = [3,4,5,6,7]
        
        [H
    |T] = [1,2,3,4]
            Succeeds 
    - binds H = 1, T = [2,3,4]
        
        [H
    |T] = [abc]
            Succeeds 
    - binds H = abc, T = []
        
        [H
    |T] = []
            Fails

    下面會給出更多模式匹配的例子,給出一個模塊用來計算列表等

    8.Erlang中函數的定義必須在一個模塊內(Module),并且模塊和函數的名稱都必須是atom,函數的參數可以是任何的Erlang類型或者數據結構,函數要被調用需要從模塊中導出,函數調用的形式類似:
    moduleName:funcName(Arg1,Arg2,...).
    寫我們的第一個Erlang程序,人見人愛的Hello World:
    -module(helloWorld).
    -export([run/1]).
    run(Name)
    ->
        io
    :format("Hello World ~w~n",[Name]).
    存為helloWorld.erl,在Erlang Shell中執行:
    2> c(helloWorld).
    {ok
    ,helloWorld}
    3> helloWorld:run(dennis).
    Hello World dennis
    ok
    打印出來了,現在解釋下程序構造,
    -module(helloWorld).
    這一行聲明了模塊helloWorld,函數必須定義在模塊內,并且模塊名稱必須與源文件名相同。
    -export([run/1]).
    而這一行聲明導出的函數,run/1指的是有一個參數的run函數,因為Erlang允許定義同名的有不同參數的多個函數,通過指定/1來說明要導出的是哪個函數。
    接下來就是函數定義了:
    run(Name)->
        io
    :format("Hello World ~w~n",[Name]).
    大寫開頭的是變量Name,調用io模塊的format方法輸出,~w可以理解成占位符,將被實際Name取代,~n就是換行了。注意,函數定義完了要以句號.結束。然后執行c(helloWorld).編譯源代碼,執行:
    helloWorld:run(dennis);

    9.內置的常用函數:
        date()
        
    time()
        
    length([1,2,3,4,5])
        size({a
    ,b,c})
        atom_to_list(an_atom)
        list_to_tuple([
    1,2,3,4])
        integer_to_list(
    2234)
        tuple_to_list({})
        hd([1,2,3,4])  %輸出1,也就是列表的head,類似Lisp的car
        tl([1,2,3,4])  %輸出[2,3,4],也就是列表的tail,類似List的cdr

    10.常見Shell命令:
    1)h(). 用來打印最近的20條歷史命令
    2)b(). 查看所有綁定的變量
    3) f(). 取消(遺忘)所有綁定的變量。
    4) f(Val).  取消指定的綁定變量
    5) e(n).   執行第n條歷史命令
    6) e(-1).  執行上一條shell命令

    11.又一個不知道怎么翻譯的概念——Guard。翻譯成約束?呵呵。用于限制變量的類型和范圍,比如:
         number(X)    - X 是數字
        integer(X)    
    - X 是整數
        float(X)    
    - X 是浮點數
        atom(X)        
    - X 是一個atom
        tuple(X)    
    - X 是一個元組
        list(X)        
    - X 是一個列表
        
        
    length(X) == 3    - X 是一個長度為3的列表
        size(X) 
    == 2    - X 是一個長度為2的元組
        
        X 
    > Y + Z    - X >Y+Z
        X 
    == Y        - X 與Y相等
        X 
    =:= Y        - X 全等于Y
        (比如: 
    1 == 1.0 成功
                   
    1 =:= 1.0 失敗)
    為了方便比較,Erlang規定如下的比較順序:
    number < atom < reference < port < pid < tuple < list
    其中pid就是process的id。

    12.忘了介紹apply函數,這個函數對于熟悉javascript的人來說很親切,javascript實現mixin就得靠它,它的調用方式如下:
    apply(Mod, Func, Args),三個參數分別是模塊、函數以及參數列表,比如調用我們的第一個Erlang程序:
    apply(helloWorld,run,[dennis]).
    13.if和case語句,if語句的結構如下:
    if
    Guard1 ->
    Sequence1 ;
    Guard2 ->
    Sequence2 ;
    ...
    end
    而case語句的結構如下:
    case Expr of
    Pattern1 [when Guard1] 
    -> Seq1;
    Pattern2 [when Guard2] 
    -> Seq2;

    PatternN [when GuardN] 
    -> SeqN
    end


    if和case語句都有一個問題,就是當沒有模式匹配或者Grard都是false的時候會導致error,這個問題case可以增加一個類似java中default的:
    case Fn of

       _ 
    ->
       true
    end
    通過_指代任意的Expr,返回true,而if可以這樣:
    if
      

      true 
    ->
       true
    end
    一樣的道理。case語句另一個需要注意的問題就是變量范圍,每個case分支中定義的變量都將默認導出case語句,也就是在case語句結束后可以被引用,因此一個規則就是每個case分支定義的變量應該一致,不然算是非法的,編譯器會給出警告,比如:
    f(X) ->
    case g(X) of
    true 
    -> A = h(X), B = A + 7;
    false 
    -> B = 6
    end
    ,
    h(A)
    .

    如果執行true分支,變量A和變量B都被定義,而如果執行的false分支,只有變量B被定義,可在case語句執行后,h(A)調用了變量A,這是不安全的,因為變量A完全可能沒有被定義,編譯器將給出警告
    variable 'A' unsafe in 'case' (line 10)



    14.給出一些稍微復雜的模型匹配例子,比如用于計算數字列表的和、平均值、長度、查找某元素是否在列表中,我們把這個模塊定義為list:
    -module(list).
    -export([average/1,sum/1,len/1,double/1,member/2]).
    average(X)
    ->sum(X)/len(X).
    sum([H
    |T]) when number(H)->H+sum(T);
    sum([])
    ->0.
    len([_
    |T])->1+len(T);
    len([])
    ->0.
    double([H
    |T]) -> [2*H|double(T)];
    double([]) 
    -> [].
    member(H
    , [H|_]) -> true;
    member(H
    , [_|T]) -> member(H, T);
    member(_
    , []) -> false.
                    

    細細體會,利用遞歸來實現,比較有趣,這其實與Lisp中利用尾遞歸來實現迭代是一樣的道理,[H|T]的形式類似Lisp中的car、cdr操作。_用于指代任意的變量,當我們只關注此處有變量,但并不關心變量的值的時候使用。用分號;來說明是同一個函數定義,只是不同的定義分支,通過模式匹配來決定調用哪個函數定義分支。
    另一個例子,計算各種圖形的面積,也是課程中給出的例子:

    -module(mathStuff).
    -export([factorial/1,area/1]).
    factorial(
    0)->1;
    factorial(N) when N
    >0->N*factorial(N-1).
    %計算正方形面積,參數元組的第一個匹配square    
    area({square
    , Side}) ->
        Side 
    * Side;
    %計算圓的面積,匹配circle  
    area({circle
    , Radius}) ->
       
    % almost :-)
       
    3 * Radius * Radius;
    %計算三角形的面積,利用海倫公式,匹配triangle 
    area({triangle
    , A, B, C}) ->
       S 
    = (A + B + C)/2,
    math
    :sqrt(S*(S-A)*(S-B)*(S-C));
    %其他
    area(Other) 
    ->
       {invalid_object
    , Other}.

    執行一下看看:
    1> c(mathStuff).
    {ok
    ,mathStuff}
    2> mathStuff:area({square,2}).
    4
    3> mathStuff:area({circle,2}).
    12
    4> mathStuff:area({triangle,2,3,4}).
    2.90474
    5> mathStuff:area({other,2,3,4}).
    {invalid_object
    ,{other,2,3,4}}

    Erlang使用%開始單行注釋。

    posted @ 2007-06-13 14:36 dennis 閱讀(29188) | 評論 (4)編輯 收藏

    看到天涯上的這個帖子:誰來救救我們的孩子?——400位父親泣血呼救。我難以呼吸,我無法相信這殘酷的現實。在21世紀的今天,竟然還有類似奴隸這樣的現象出現,這就是我的祖國,這就是和諧社會。我幫不了那些孩子,我只好把這個帖子寫在blog里,讓更多人知道,讓更多人思考。

    posted @ 2007-06-12 11:40 dennis 閱讀(698) | 評論 (1)編輯 收藏

    習題2.17,直接利用list-ref和length過程
    (define (last-pair items)
      (list (list
    -ref items (- (length items) 1))))

    習題2.18,采用迭代法
    (define (reverse-list items)
      (define (reverse
    -iter i k)
        (
    if (null? i) k (reverse-iter (cdr i) (cons (car i) k))))
      (reverse
    -iter items ()))
    習題2.20,如果兩個數的奇偶相同,那么他們的差模2等于0,根據這一點可以寫出:
    (define (same-parity a . b)
      (define (same
    -parity-temp x y)
      (cond ((
    null? y) y)
            ((
    = (remainder (- (car y) x) 20)
             (cons (car y) (same
    -parity-temp x (cdr y))))
            (
    else
               (same
    -parity-temp x (cdr y)))))
      (cons a (same
    -parity-temp a b)))
    利用了基本過程remainder取模

    習題2.21,遞歸方式:
    (define (square-list items)
      (
    if (null? items)
          items 
          (cons (square (car items)) (square
    -list (cdr items)))))
    利用map過程:
    (define (square-list items)
      (map square items))

    習題2.23,這與ruby中的each是一樣的意思,將操作應用于集合的每個元素:
    (define (for-each proc items)
      (define (
    for-each-temp proc temp items)
      (
    if (null? items)
          #t
          (
    for-each-temp proc (proc (car items)) (cdr items))))
      (
    for-each-temp proc 0 items))
    最后返回true

    習題2.24,盒子圖就不畫了,麻煩,解釋器輸出:
    Welcome to DrScheme, version 360.
    Language: Standard (R5RS).
    > (list 1 (list 2 (list 3 4)))
    (
    1 (2 (3 4)))
    樹形狀應當是這樣
                   . 
    /\
    / \
    1 .
    /\
    / \
    2 .
    /\
    / \
    3 4
    習題2.25,
    第一個list可以表示為(list 1 3 (list 5 7) 9)
    因此取7的操作應當是:
    (car (cdr (car (cdr (cdr (list 1 3 (list 5 79))))))
    第二個list表示為:(list (list 7))
    因此取7操作為:
    (car (car (list (list 7))))

    第三個list可以表示為:
    (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7))))))
    因此取7的操作為:
    (define x (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7)))))))
    (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr x))))))))))))
    夠恐怖!-_-

    習題2.26,純粹的動手題,就不說了
    習題2.27,在reverse的基礎上進行修改,同樣采用迭代,比較難理解:

    (define (deep-reverse x)
      (define (reverse
    -iter rest result)
        (cond ((null? rest) result)
              ((
    not (pair? (car rest)))
               (reverse
    -iter (cdr rest)
                     (cons (car rest) result)))
              (
    else
               (reverse
    -iter (cdr rest)
                     (cons (deep
    -reverse (car rest)) result)))
               ))
      (reverse
    -iter x ()))

    習題2.28,遞歸,利用append過程就容易了:
    (define (finge x)
      (cond ((pair? x) (append (finge (car x)) (finge (cdr x))))
            ((null? x) ())
            (
    else (list x))))

    習題2.29,這一題很明顯出來的二叉活動體也是個層次性的樹狀結構
    1)很簡單,利用car,cdr
    (define (left-branch x)
      (car x))
    (define (right
    -branch x)
      (car (cdr x)))
    (define (branch
    -length b)
      (car b))
    (define (branch
    -structure b)
      (car (cdr b)))

    2)首先需要一個過程用于求解分支的總重量:
    (define (branch-weight branch)
      (let ((structure (branch
    -structure branch)))
        (
    if (not (pair? structure))
            structure
            (total
    -weight structure))))
    (define (total
    -weight mobile)
      (
    + (branch-weight (left-branch mobile))
         (branch
    -weight (right-branch mobile))))

    利用這個過程寫出balanced?過程:
    (define (torque branch)
      (
    * (branch-length branch) (branch-weight branch)))
    (define (balanced? mobile)
      (
    = (torque (left-branch mobile))
         (torque (right
    -branch mobile))))

    3)選擇函數和定義函數提供了一層抽象屏蔽,其他函數都是建立在這兩個基礎上,因此需要改變的僅僅是selector函數:
    (define (right-branch mobile) (cdr mobile))
    (define (branch
    -structure branch) (cdr branch))

    習題2.30:
    (define (square-tree tree)
      (cond ((null? tree) tree)
            ((
    not (pair? tree)) (square tree))
            (
    else
               (cons (square
    -tree (car tree)) (square-tree (cdr tree))))))
    (define (square
    -tree2 tree)
      (map (
    lambda(x)
             (
    if (pair? x)
                 (square
    -tree x)
                 (square x))) tree))

    習題2.31,進一步抽象出map-tree,與map過程類似,將proc過程作用于樹的每個節點:
    (define (tree-map proc tree)
      (cond ((null? tree) tree)
            ((
    not (pair? tree)) (proc tree))
            (
    else
               (cons (tree
    -map proc (car tree)) (tree-map proc (cdr tree))))))
    (define (square
    -tree3 tree)
      (tree
    -map square tree))

    習題2.32,通過觀察,rest總是cdr后的子集,比如對于(list 1 2 3),連續cdr出來的是:
    (2 3)
    (3)
    ()
    其他的5個子集應該是car結果與這些子集組合的結果,因此:
    (define (subsets s)
      (
    if (null? s)
          (list s)
          (let ((rest (subsets (cdr s))))
            (append rest (map (
    lambda(x) (cons (car s) x)) rest)))))


    posted @ 2007-06-12 09:55 dennis 閱讀(1088) | 評論 (2)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 38 39 40 41 42 43 44 45 46 下一頁 Last 
    主站蜘蛛池模板: 国产啪精品视频网站免费尤物| 亚洲人成无码www久久久| 亚洲国产一区明星换脸| 久久久久亚洲AV无码专区网站| 色偷偷噜噜噜亚洲男人| 在线看无码的免费网站| 亚洲第一区精品日韩在线播放| 久久亚洲精品11p| 亚洲Av无码乱码在线观看性色| 国产精品亚洲五月天高清| 俄罗斯极品美女毛片免费播放| 99人中文字幕亚洲区| 亚洲国产精品免费在线观看| 亚洲欧洲国产视频| 免费人成在线观看视频高潮| 亚洲精品美女久久久久99| 你懂的免费在线观看网站| 久久久亚洲欧洲日产国码是AV| 19禁啪啪无遮挡免费网站| 亚洲天堂免费在线| 国产jizzjizz视频全部免费| 亚洲人成片在线观看| 午夜毛片不卡高清免费| 亚洲精品福利在线观看| 在线观看视频免费完整版| 久久精品蜜芽亚洲国产AV| 99久久免费国产精品特黄| 精品特级一级毛片免费观看| 久久亚洲国产精品123区| 91大神免费观看| 亚洲成av人片在线天堂无| 中文字幕亚洲不卡在线亚瑟| 91精品国产免费久久国语麻豆| 亚洲国产日韩综合久久精品| 无码欧精品亚洲日韩一区夜夜嗨 | 18禁网站免费无遮挡无码中文| 亚洲狠狠成人综合网| 亚洲综合国产精品第一页| 99精品热线在线观看免费视频| 久久精品亚洲综合专区| 国产精品视频免费一区二区|