莊周夢(mèng)蝶

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

              今天同事遇到的問題,用JRuby調(diào)用一個(gè)java方法,該方法使用了jdk1.5的可變參數(shù)。我一開始以為只要簡(jiǎn)單地將可變參數(shù)表示為數(shù)組即可,例如下面的兩個(gè)java類:
          public class Echo{
              
          public void echo(String name){
                 System.out.println(name);
              }
          }
          public class Test{
              
          public void hello(String name,Echoargs){
                  System.out.println(
          "hello,"+name);
                  
          for(Echo e:args){
                      e.echo(name);
                  }
              }
          }
             我想在jruby中調(diào)用Test的hello方法,該方法有個(gè)可變參數(shù)args。所謂可變參數(shù)經(jīng)過編譯后其實(shí)也就是數(shù)組,這個(gè)可以通過觀察字節(jié)碼知道,那么如果用數(shù)組來調(diào)用可以不?
          require 'java'
          require 
          'test.jar'
          include_class 
          'Test'
          include_class 
          'Echo'
          t.hello(
          "dennis")  #報(bào)錯(cuò),參數(shù)不匹配
          t.hello("dennis",[])  #報(bào)錯(cuò),類型不匹配
             很遺憾,這樣調(diào)用是錯(cuò)誤的,原因如上面的注釋。具體到類型不匹配,本質(zhì)的原因是JRuby中的數(shù)組與java中對(duì)數(shù)組的字節(jié)碼表示是不一致的,JRuby中的數(shù)組是用org.jruby.RubyArray類來表示,而hello方法需要的數(shù)組卻是是[LEcho。解決的辦法就是將JRuby的數(shù)組轉(zhuǎn)成java需要的類型,通過to_java方法,因而下面的調(diào)用才是正確的,盡管顯的麻煩:
          require 'java'
          require 
          'test.jar'
          include_class 
          'Test'
          include_class 
          'Echo'
          t
          =Test.new
          t.hello(
          "dennis",[].to_java("Echo"))
          e1
          =Echo.new
          t.hello(
          "dennis",[e1].to_java("Echo"))
          e2
          =Echo.new
          t.hello(
          "dennis",[e1,e2].to_java("Echo"))


          posted @ 2008-06-14 22:39 dennis 閱讀(2185) | 評(píng)論 (1)編輯 收藏

               頭發(fā)乃人之元,很多人看人,第一眼看的就是你的頭發(fā),當(dāng)然看MM的部位可能不一樣。我的頭發(fā)從來都是像野草一樣,從來沒放心思在上面,都是理一次頭發(fā)大半年不管他,長(zhǎng)的跟雜草似的難受,然后回家找小區(qū)內(nèi)的師傅理發(fā)——或者說剃頭,而且發(fā)型從來都是板寸頭,短短的,免的大半年不回家還得在外面理發(fā)。因而,我的理發(fā)時(shí)間跟我的回家時(shí)間一樣。

          小時(shí)候,那時(shí)候住在老家,沒有專門的理發(fā)店,也可能是離我家的小村莊很遠(yuǎn)。有個(gè)走村串戶的剃頭匠,大概幾個(gè)月能在村里見他一次,帶著一身行頭,誰家有人要剃頭,就請(qǐng)他過去。記的那時(shí)是沒用電的理發(fā)工具,一把類似夾子的東西,老師傅手工在各式各樣的腦袋上推來推去,然后搞些肥皂水就著自家的井水沖洗。后來很久沒再見到這位老師傅,而隔壁村開了家理發(fā)店,大人們就帶著我們走路或者騎著自行車去隔壁村剃頭了,記的那位師傅還是我們大隊(duì)的干部,隔壁是豬肉店,至于剃頭的細(xì)節(jié)卻是記不清了。再后來隔壁村又開了一家理發(fā)店,是個(gè)小青年開的,印象特別深的一次是我奶奶帶我過去理發(fā),小青年說如果我?guī)退蛞煌熬?,錢可以減半。我?guī)退蛄送熬缓笳娼o我減半了,就著自己打的井水沖洗我的不規(guī)則的大腦袋。后來,跟父母搬到了縣城,去外地讀書,就再也沒在老家理發(fā)過了,好幾年之后路過小青年開的那家店,裝修了,藍(lán)色的玻璃后面,小青年變成了師傅,指導(dǎo)著自己的徒弟在理發(fā),我想,大概他也記不得當(dāng)年那個(gè)給他打水的小屁孩了。

          進(jìn)城了,我理發(fā)就固定在小區(qū)的周師傅這了。上大學(xué),基本是五一、十一和春節(jié)回家的時(shí)候剃一次,哪怕再長(zhǎng),還是不愿意在福州理發(fā),分不清是習(xí)慣還是莫名其妙的堅(jiān)持了。其實(shí)挺不好意思的,每次都留那么長(zhǎng)的頭發(fā),周師傅也還是固定收我5塊錢,不過今年漲價(jià)了,7塊。下午剃頭的時(shí)候,周師傅的女兒找他要100來塊錢,旁邊的人問周師傅她拿去做啥呢?周師傅說去染發(fā),語氣有點(diǎn)黯然。父親理的老式發(fā)型,女兒是不會(huì)喜歡的。我的頭發(fā)就這樣隨著我離家的遠(yuǎn)近輪回著,現(xiàn)在在廣州,回家還是容易的,以后去哪還是不知道的事情,希望還能半年回家一次理發(fā)。

          posted @ 2008-06-13 21:54 dennis 閱讀(589) | 評(píng)論 (4)編輯 收藏

          Hadoop分布式文件系統(tǒng):架構(gòu)和設(shè)計(jì)要點(diǎn)
          原文:http://hadoop.apache.org/core/docs/current/hdfs_design.html
          一、前提和設(shè)計(jì)目標(biāo)
          1、硬件錯(cuò)誤是常態(tài),而非異常情況,HDFS可能是有成百上千的server組成,任何一個(gè)組件都有可能一直失效,因此錯(cuò)誤檢測(cè)和快速、自動(dòng)的恢復(fù)是HDFS的核心架構(gòu)目標(biāo)。
          2、跑在HDFS上的應(yīng)用與一般的應(yīng)用不同,它們主要是以流式讀為主,做批量處理;比之關(guān)注數(shù)據(jù)訪問的低延遲問題,更關(guān)鍵的在于數(shù)據(jù)訪問的高吞吐量。
          3、HDFS以支持大數(shù)據(jù)集合為目標(biāo),一個(gè)存儲(chǔ)在上面的典型文件大小一般都在千兆至T字節(jié),一個(gè)單一HDFS實(shí)例應(yīng)該能支撐數(shù)以千萬計(jì)的文件。
          4、 HDFS應(yīng)用對(duì)文件要求的是write-one-read-many訪問模型。一個(gè)文件經(jīng)過創(chuàng)建、寫,關(guān)閉之后就不需要改變。這一假設(shè)簡(jiǎn)化了數(shù)據(jù)一致性問 題,使高吞吐量的數(shù)據(jù)訪問成為可能。典型的如MapReduce框架,或者一個(gè)web crawler應(yīng)用都很適合這個(gè)模型。
          5、移動(dòng)計(jì)算的代價(jià)比之移動(dòng)數(shù)據(jù)的代價(jià)低。一個(gè)應(yīng)用請(qǐng)求的計(jì)算,離它操作的數(shù)據(jù)越近就越高效,這在數(shù)據(jù)達(dá)到海量級(jí)別的時(shí)候更是如此。將計(jì)算移動(dòng)到數(shù)據(jù)附近,比之將數(shù)據(jù)移動(dòng)到應(yīng)用所在顯然更好,HDFS提供給應(yīng)用這樣的接口。
          6、在異構(gòu)的軟硬件平臺(tái)間的可移植性。

          二、NamenodeDatanode
              HDFS采用master/slave架構(gòu)。一個(gè)HDFS集群是有一個(gè)Namenode和一定數(shù)目的Datanode組成。Namenode是一個(gè)中心服 務(wù)器,負(fù)責(zé)管理文件系統(tǒng)的namespace和客戶端對(duì)文件的訪問。Datanode在集群中一般是一個(gè)節(jié)點(diǎn)一個(gè),負(fù)責(zé)管理節(jié)點(diǎn)上它們附帶的存儲(chǔ)。在內(nèi) 部,一個(gè)文件其實(shí)分成一個(gè)或多個(gè)block,這些block存儲(chǔ)在Datanode集合里。Namenode執(zhí)行文件系統(tǒng)的namespace操作,例如 打開、關(guān)閉、重命名文件和目錄,同時(shí)決定block到具體Datanode節(jié)點(diǎn)的映射。DatanodeNamenode的指揮下進(jìn)行block的創(chuàng) 建、刪除和復(fù)制。NamenodeDatanode都是設(shè)計(jì)成可以跑在普通的廉價(jià)的運(yùn)行linux的機(jī)器上。HDFS采用java語言開發(fā),因此可以部 署在很大范圍的機(jī)器上。一個(gè)典型的部署場(chǎng)景是一臺(tái)機(jī)器跑一個(gè)單獨(dú)的Namenode節(jié)點(diǎn),集群中的其他機(jī)器各跑一個(gè)Datanode實(shí)例。這個(gè)架構(gòu)并不排 除一臺(tái)機(jī)器上跑多個(gè)Datanode,不過這比較少見。

          單一節(jié)點(diǎn)的Namenode大大簡(jiǎn)化了系統(tǒng)的架構(gòu)。Namenode負(fù)責(zé)保管和管理所有的HDFS元數(shù)據(jù),因而用戶數(shù)據(jù)就不需要通過Namenode(也就是說文件數(shù)據(jù)的讀寫是直接在Datanode上)。

          三、文件系統(tǒng)的namespace
             HDFS支持傳統(tǒng)的層次型文件組織,與大多數(shù)其他文件系統(tǒng)類似,用戶可以創(chuàng)建目錄,并在其間創(chuàng)建、刪除、移動(dòng)和重命名文件。HDFS不支持user quotas和訪問權(quán)限,也不支持鏈接(link),不過當(dāng)前的架構(gòu)并不排除實(shí)現(xiàn)這些特性。Namenode維護(hù)文件系統(tǒng)的namespace,任何對(duì)文 件系統(tǒng)namespace和文件屬性的修改都將被Namenode記錄下來。應(yīng)用可以設(shè)置HDFS保存的文件的副本數(shù)目,文件副本的數(shù)目稱為文件的 replication因子,這個(gè)信息也是由Namenode保存。

          四、數(shù)據(jù)復(fù)制
              HDFS被設(shè)計(jì)成在一個(gè)大集群中可以跨機(jī)器地可靠地存儲(chǔ)海量的文件。它將每個(gè)文件存儲(chǔ)成block序列,除了最后一個(gè)block,所有的block都是同 樣的大小。文件的所有block為了容錯(cuò)都會(huì)被復(fù)制。每個(gè)文件的block大小和replication因子都是可配置的。Replication因子可 以在文件創(chuàng)建的時(shí)候配置,以后也可以改變。HDFS中的文件是write-one,并且嚴(yán)格要求在任何時(shí)候只有一個(gè)writer。Namenode全權(quán)管 理block的復(fù)制,它周期性地從集群中的每個(gè)Datanode接收心跳包和一個(gè)Blockreport。心跳包的接收表示該Datanode節(jié)點(diǎn)正常工 作,而Blockreport包括了該Datanode上所有的block組成的列表。


          1、副本的存放,副本的存放是HDFS可靠性和性能的關(guān)鍵。HDFS采用一種稱為rack-aware的策略來改進(jìn)數(shù)據(jù)的可靠性、有效性和網(wǎng)絡(luò)帶寬的利 用。這個(gè)策略實(shí)現(xiàn)的短期目標(biāo)是驗(yàn)證在生產(chǎn)環(huán)境下的表現(xiàn),觀察它的行為,構(gòu)建測(cè)試和研究的基礎(chǔ),以便實(shí)現(xiàn)更先進(jìn)的策略。龐大的HDFS實(shí)例一般運(yùn)行在多個(gè)機(jī) 架的計(jì)算機(jī)形成的集群上,不同機(jī)架間的兩臺(tái)機(jī)器的通訊需要通過交換機(jī),顯然通常情況下,同一個(gè)機(jī)架內(nèi)的兩個(gè)節(jié)點(diǎn)間的帶寬會(huì)比不同機(jī)架間的兩臺(tái)機(jī)器的帶寬 大。
              通過一個(gè)稱為Rack Awareness的過程,Namenode決定了每個(gè)Datanode所屬的rack id。一個(gè)簡(jiǎn)單但沒有優(yōu)化的策略就是將副本存放在單獨(dú)的機(jī)架上。這樣可以防止整個(gè)機(jī)架(非副本存放)失效的情況,并且允許讀數(shù)據(jù)的時(shí)候可以從多個(gè)機(jī)架讀 取。這個(gè)簡(jiǎn)單策略設(shè)置可以將副本分布在集群中,有利于組件失敗情況下的負(fù)載均衡。但是,這個(gè)簡(jiǎn)單策略加大了寫的代價(jià),因?yàn)橐粋€(gè)寫操作需要傳輸block到 多個(gè)機(jī)架。
              在大多數(shù)情況下,replication因子是3HDFS的存放策略是將一個(gè)副本存放在本地機(jī)架上的節(jié)點(diǎn),一個(gè)副本放在同一機(jī)架上的另一個(gè)節(jié)點(diǎn),最后一 個(gè)副本放在不同機(jī)架上的一個(gè)節(jié)點(diǎn)。機(jī)架的錯(cuò)誤遠(yuǎn)遠(yuǎn)比節(jié)點(diǎn)的錯(cuò)誤少,這個(gè)策略不會(huì)影響到數(shù)據(jù)的可靠性和有效性。三分之一的副本在一個(gè)節(jié)點(diǎn)上,三分之二在一個(gè) 機(jī)架上,其他保存在剩下的機(jī)架中,這一策略改進(jìn)了寫的性能。

          2、副本的選擇,為了降低整體的帶寬消耗和讀延時(shí),HDFS會(huì)盡量讓reader讀最近的副本。如果在reader的同一個(gè)機(jī)架上有一個(gè)副本,那么就讀該副本。如果一個(gè)HDFS集群跨越多個(gè)數(shù)據(jù)中心,那么reader也將首先嘗試讀本地?cái)?shù)據(jù)中心的副本。

          3SafeMode
              Namenode啟動(dòng)后會(huì)進(jìn)入一個(gè)稱為SafeMode的特殊狀態(tài),處在這個(gè)狀態(tài)的Namenode是不會(huì)進(jìn)行數(shù)據(jù)塊的復(fù)制的。Namenode從所有的 Datanode接收心跳包和Blockreport。Blockreport包括了某個(gè)Datanode所有的數(shù)據(jù)塊列表。每個(gè)block都有指定的最 小數(shù)目的副本。當(dāng)Namenode檢測(cè)確認(rèn)某個(gè)Datanode的數(shù)據(jù)塊副本的最小數(shù)目,那么該Datanode就會(huì)被認(rèn)為是安全的;如果一定百分比(這 個(gè)參數(shù)可配置)的數(shù)據(jù)塊檢測(cè)確認(rèn)是安全的,那么Namenode將退出SafeMode狀態(tài),接下來它會(huì)確定還有哪些數(shù)據(jù)塊的副本沒有達(dá)到指定數(shù)目,并將 這些block復(fù)制到其他Datanode。

          五、文件系統(tǒng)元數(shù)據(jù)的持久化
              Namenode存儲(chǔ)HDFS的元數(shù)據(jù)。對(duì)于任何對(duì)文件元數(shù)據(jù)產(chǎn)生修改的操作,Namenode都使用一個(gè)稱為Editlog的事務(wù)日志記錄下來。例如, 在HDFS中創(chuàng)建一個(gè)文件,Namenode就會(huì)在Editlog中插入一條記錄來表示;同樣,修改文件的replication因子也將往 Editlog插入一條記錄。Namenode在本地OS的文件系統(tǒng)中存儲(chǔ)這個(gè)Editlog。整個(gè)文件系統(tǒng)的namespace,包括block到文件 的映射、文件的屬性,都存儲(chǔ)在稱為FsImage的文件中,這個(gè)文件也是放在Namenode所在系統(tǒng)的文件系統(tǒng)上。
              Namenode在內(nèi)存中保存著整個(gè)文件系統(tǒng)namespace和文件Blockmap的映像。這個(gè)關(guān)鍵的元數(shù)據(jù)設(shè)計(jì)得很緊湊,因而一個(gè)帶有4G內(nèi)存的 Namenode足夠支撐海量的文件和目錄。當(dāng)Namenode啟動(dòng)時(shí),它從硬盤中讀取EditlogFsImage,將所有Editlog中的事務(wù)作 用(apply)在內(nèi)存中的FsImage ,并將這個(gè)新版本的FsImage從內(nèi)存中flush到硬盤上,然后再truncate這個(gè)舊的Editlog,因?yàn)檫@個(gè)舊的Editlog的事務(wù)都已經(jīng) 作用在FsImage上了。這個(gè)過程稱為checkpoint。在當(dāng)前實(shí)現(xiàn)中,checkpoint只發(fā)生在Namenode啟動(dòng)時(shí),在不久的將來我們將 實(shí)現(xiàn)支持周期性的checkpoint。
              Datanode并不知道關(guān)于文件的任何東西,除了將文件中的數(shù)據(jù)保存在本地的文件系統(tǒng)上。它把每個(gè)HDFS數(shù)據(jù)塊存儲(chǔ)在本地文件系統(tǒng)上隔離的文件中。 Datanode并不在同一個(gè)目錄創(chuàng)建所有的文件,相反,它用啟發(fā)式地方法來確定每個(gè)目錄的最佳文件數(shù)目,并且在適當(dāng)?shù)臅r(shí)候創(chuàng)建子目錄。在同一個(gè)目錄創(chuàng)建 所有的文件不是最優(yōu)的選擇,因?yàn)楸镜匚募到y(tǒng)可能無法高效地在單一目錄中支持大量的文件。當(dāng)一個(gè)Datanode啟動(dòng)時(shí),它掃描本地文件系統(tǒng),對(duì)這些本地 文件產(chǎn)生相應(yīng)的一個(gè)所有HDFS數(shù)據(jù)塊的列表,然后發(fā)送報(bào)告到Namenode,這個(gè)報(bào)告就是Blockreport。

          六、通訊協(xié)議
              所有的HDFS通訊協(xié)議都是構(gòu)建在TCP/IP協(xié)議上。客戶端通過一個(gè)可配置的端口連接到Namenode,通過ClientProtocolNamenode交互。而Datanode是使用DatanodeProtocolNamenode交互。從ClientProtocolDatanodeprotocol抽象出一個(gè)遠(yuǎn)程調(diào)用(RPC),在設(shè)計(jì)上,Namenode不會(huì)主動(dòng)發(fā)起RPC,而是是響應(yīng)來自客戶端和 Datanode RPC請(qǐng)求。

          七、健壯性
              HDFS的主要目標(biāo)就是實(shí)現(xiàn)在失敗情況下的數(shù)據(jù)存儲(chǔ)可靠性。常見的三種失?。?/span>Namenode failures, Datanode failures和網(wǎng)絡(luò)分割(network partitions)。
          1、硬盤數(shù)據(jù)錯(cuò)誤、心跳檢測(cè)和重新復(fù)制
              每個(gè)Datanode節(jié)點(diǎn)都向Namenode周期性地發(fā)送心跳包。網(wǎng)絡(luò)切割可能導(dǎo)致一部分DatanodeNamenode失去聯(lián)系。 Namenode通過心跳包的缺失檢測(cè)到這一情況,并將這些Datanode標(biāo)記為dead,不會(huì)將新的IO請(qǐng)求發(fā)給它們。寄存在dead Datanode上的任何數(shù)據(jù)將不再有效。Datanode的死亡可能引起一些block的副本數(shù)目低于指定值,Namenode不斷地跟蹤需要復(fù)制的 block,在任何需要的情況下啟動(dòng)復(fù)制。在下列情況可能需要重新復(fù)制:某個(gè)Datanode節(jié)點(diǎn)失效,某個(gè)副本遭到損壞,Datanode上的硬盤錯(cuò) 誤,或者文件的replication因子增大。

          2、集群均衡
             HDFS支持?jǐn)?shù)據(jù)的均衡計(jì)劃,如果某個(gè)Datanode節(jié)點(diǎn)上的空閑空間低于特定的臨界點(diǎn),那么就會(huì)啟動(dòng)一個(gè)計(jì)劃自動(dòng)地將數(shù)據(jù)從一個(gè)Datanode搬移 到空閑的Datanode。當(dāng)對(duì)某個(gè)文件的請(qǐng)求突然增加,那么也可能啟動(dòng)一個(gè)計(jì)劃創(chuàng)建該文件新的副本,并分布到集群中以滿足應(yīng)用的要求。這些均衡計(jì)劃目前 還沒有實(shí)現(xiàn)。

          3、數(shù)據(jù)完整性
            從某個(gè)Datanode獲取的數(shù)據(jù)塊有可能是損壞的,這個(gè)損壞可能是由于Datanode的存儲(chǔ)設(shè)備錯(cuò)誤、網(wǎng)絡(luò)錯(cuò)誤或者軟件bug造成的。HDFS客戶端 軟件實(shí)現(xiàn)了HDFS文件內(nèi)容的校驗(yàn)和。當(dāng)某個(gè)客戶端創(chuàng)建一個(gè)新的HDFS文件,會(huì)計(jì)算這個(gè)文件每個(gè)block的校驗(yàn)和,并作為一個(gè)單獨(dú)的隱藏文件保存這些 校驗(yàn)和在同一個(gè)HDFS namespace下。當(dāng)客戶端檢索文件內(nèi)容,它會(huì)確認(rèn)從Datanode獲取的數(shù)據(jù)跟相應(yīng)的校驗(yàn)和文件中的校驗(yàn)和是否匹配,如果不匹配,客戶端可以選擇 從其他Datanode獲取該block的副本。

          4、元數(shù)據(jù)磁盤錯(cuò)誤
              FsImageEditlogHDFS的核心數(shù)據(jù)結(jié)構(gòu)。這些文件如果損壞了,整個(gè)HDFS實(shí)例都將失效。因而,Namenode可以配置成支持維護(hù)多 個(gè)FsImageEditlog的拷貝。任何對(duì)FsImage或者Editlog的修改,都將同步到它們的副本上。這個(gè)同步操作可能會(huì)降低 Namenode每秒能支持處理的namespace事務(wù)。這個(gè)代價(jià)是可以接受的,因?yàn)?/span>HDFS是數(shù)據(jù)密集的,而非元數(shù)據(jù)密集。當(dāng)Namenode重啟的 時(shí)候,它總是選取最近的一致的FsImageEditlog使用。
             NamenodeHDFS是單點(diǎn)存在,如果Namenode所在的機(jī)器錯(cuò)誤,手工的干預(yù)是必須的。目前,在另一臺(tái)機(jī)器上重啟因故障而停止服務(wù)的Namenode這個(gè)功能還沒實(shí)現(xiàn)。

          5、快照
             快照支持某個(gè)時(shí)間的數(shù)據(jù)拷貝,當(dāng)HDFS數(shù)據(jù)損壞的時(shí)候,可以恢復(fù)到過去一個(gè)已知正確的時(shí)間點(diǎn)。HDFS目前還不支持快照功能。

          八、數(shù)據(jù)組織
          1、數(shù)據(jù)塊
              兼容HDFS的應(yīng)用都是處理大數(shù)據(jù)集合的。這些應(yīng)用都是寫數(shù)據(jù)一次,讀卻是一次到多次,并且讀的速度要滿足流式讀。HDFS支持文件的write- once-read-many語義。一個(gè)典型的block大小是64MB,因而,文件總是按照64M切分成chunk,每個(gè)chunk存儲(chǔ)于不同的 Datanode
          2、步驟
              某個(gè)客戶端創(chuàng)建文件的請(qǐng)求其實(shí)并沒有立即發(fā)給Namenode,事實(shí)上,HDFS客戶端會(huì)將文件數(shù)據(jù)緩存到本地的一個(gè)臨時(shí)文件。應(yīng)用的寫被透明地重定向到 這個(gè)臨時(shí)文件。當(dāng)這個(gè)臨時(shí)文件累積的數(shù)據(jù)超過一個(gè)block的大?。J(rèn)64M),客戶端才會(huì)聯(lián)系Namenode。Namenode將文件名插入文件系 統(tǒng)的層次結(jié)構(gòu)中,并且分配一個(gè)數(shù)據(jù)塊給它,然后返回Datanode的標(biāo)識(shí)符和目標(biāo)數(shù)據(jù)塊給客戶端。客戶端將本地臨時(shí)文件flush到指定的 Datanode上。當(dāng)文件關(guān)閉時(shí),在臨時(shí)文件中剩余的沒有flush的數(shù)據(jù)也會(huì)傳輸?shù)街付ǖ?/span>Datanode,然后客戶端告訴Namenode文件已經(jīng) 關(guān)閉。此時(shí)Namenode才將文件創(chuàng)建操作提交到持久存儲(chǔ)。如果Namenode在文件關(guān)閉前掛了,該文件將丟失。
             上述方法是對(duì)通過對(duì)HDFS上運(yùn)行的目標(biāo)應(yīng)用認(rèn)真考慮的結(jié)果。如果不采用客戶端緩存,由于網(wǎng)絡(luò)速度和網(wǎng)絡(luò)堵塞會(huì)對(duì)吞估量造成比較大的影響。

          3、流水線復(fù)制
              當(dāng)某個(gè)客戶端向HDFS文件寫數(shù)據(jù)的時(shí)候,一開始是寫入本地臨時(shí)文件,假設(shè)該文件的replication因子設(shè)置為3,那么客戶端會(huì)從Namenode 獲取一張Datanode列表來存放副本。然后客戶端開始向第一個(gè)Datanode傳輸數(shù)據(jù),第一個(gè)Datanode一小部分一小部分(4kb)地接收數(shù) 據(jù),將每個(gè)部分寫入本地倉(cāng)庫(kù),并且同時(shí)傳輸該部分到第二個(gè)Datanode節(jié)點(diǎn)。第二個(gè)Datanode也是這樣,邊收邊傳,一小部分一小部分地收,存儲(chǔ) 在本地倉(cāng)庫(kù),同時(shí)傳給第三個(gè)Datanode,第三個(gè)Datanode就僅僅是接收并存儲(chǔ)了。這就是流水線式的復(fù)制。

          九、可訪問性
              HDFS給應(yīng)用提供了多種訪問方式,可以通過DFSShell通過命令行與HDFS數(shù)據(jù)進(jìn)行交互,可以通過java API調(diào)用,也可以通過C語言的封裝API訪問,并且提供了瀏覽器訪問的方式。正在開發(fā)通過WebDav協(xié)議訪問的方式。具體使用參考文檔。
          十、空間的回收
          1、文件的刪除和恢復(fù)
              用戶或者應(yīng)用刪除某個(gè)文件,這個(gè)文件并沒有立刻從HDFS中刪除。相反,HDFS將這個(gè)文件重命名,并轉(zhuǎn)移到/trash目錄。當(dāng)文件還在/trash目 錄時(shí),該文件可以被迅速地恢復(fù)。文件在/trash中保存的時(shí)間是可配置的,當(dāng)超過這個(gè)時(shí)間,Namenode就會(huì)將該文件從namespace中刪除。 文件的刪除,也將釋放關(guān)聯(lián)該文件的數(shù)據(jù)塊。注意到,在文件被用戶刪除和HDFS空閑空間的增加之間會(huì)有一個(gè)等待時(shí)間延遲。
              當(dāng)被刪除的文件還保留在/trash目錄中的時(shí)候,如果用戶想恢復(fù)這個(gè)文件,可以檢索瀏覽/trash目錄并檢索該文件。/trash目錄僅僅保存被刪除 文件的最近一次拷貝。/trash目錄與其他文件目錄沒有什么不同,除了一點(diǎn):HDFS在該目錄上應(yīng)用了一個(gè)特殊的策略來自動(dòng)刪除文件,目前的默認(rèn)策略是 刪除保留超過6小時(shí)的文件,這個(gè)策略以后會(huì)定義成可配置的接口。

          2Replication因子的減小
              當(dāng)某個(gè)文件的replication因子減小,Namenode會(huì)選擇要?jiǎng)h除的過剩的副本。下次心跳檢測(cè)就將該信息傳遞給Datanode, Datanode就會(huì)移除相應(yīng)的block并釋放空間,同樣,在調(diào)用setReplication方法和集群中的空閑空間增加之間會(huì)有一個(gè)時(shí)間延遲。

          參考資料:
          HDFS Java API: http://hadoop.apache.org/core/docs/current/api/
          HDFS source code: http://hadoop.apache.org/core/version_control.html
             







          posted @ 2008-06-05 14:29 dennis 閱讀(53386) | 評(píng)論 (25)編輯 收藏

              當(dāng)將用scheme寫的scheme求值器跑起來的時(shí)候,你不覺的興奮是不可能的,真的太酷了,太magic了。
          習(xí)題4.2,如果將application?判斷放在define?判斷之前,那么求值(define x 3)將把define當(dāng)作一般的procedure應(yīng)用于參數(shù)x和3,可是define是特殊的語法形式,而非一般過程,導(dǎo)致出錯(cuò)。
          習(xí)題4.4,我的解答,eval增加兩個(gè)判斷:
           ((and? exp)
             (eval
          -and (and-exps exp) env))
           ((or
          ? exp)
             (eval
          -or (or-exps exp) env))
          實(shí)現(xiàn)謂詞和各自的過程:
          (define (and? exp) 
            (tagged
          -list? exp 'and))
          (define (and-exps exp)
            (cdr exp))
          (define (eval
          -and exps env)
            (cond ((
          null? exps)
                    
          'true)
                  (else
                    (let ((result (eval (car exps) env)))
                      (
          if (not result)
                          result
                          (eval
          -and (cdr exps) env))))))
          (define (or
          ? exp)
            (tagged
          -list? exp 'or))
          (define (or-exps exp) (cdr exp))
          (define (eval
          -or exps env)
            (cond ((
          null? exps)
                   
          'false)
                  (else
                   (let ((result (eval (car exps) env)))
                     (
          if result
                         result
                         (eval
          -or (cdr exps) env))))))

          如果用宏實(shí)現(xiàn)就簡(jiǎn)單了:
          (define-syntax and
            (syntax
          -rules ()
                ((_) #t)
                ((_ e) e)
                ((_ e1 e2 e3 )
                  (
          if e1 (and e2 e3 ) #f))))
          (define
          -syntax or
             (syntax
          -rules ()
                       ((_) #f)
                       ((_ e) e)
                       ((_ e1 e2 e3 )
                        (let ((t e1))
                            (
          if t t (or e2 e3 ))))))

          習(xí)題4.5,cond的擴(kuò)展形式,也不難,在else子句之外增加個(gè)判斷,是否帶有=>符號(hào),修改expand-clauses過程:
          (define (cond-extended-clauses? clause)
            (and (> (length clause) 2) (eq? (cadr clause) '=>)))
          (define (extended-cond-test clause)
            (car clause))
          (define (extended-cond-recipient clause)
            (caddr clause)
          (define (expand
          -clauses clauses)
            (
          if (null? clauses)
                
          'false
                (let ((first (car clauses))
                      (rest (cdr clauses)))
                  (cond ((cond
          -else-clauses? first)
                          (
          if (null? rest)
                              (sequence
          ->exp (cond-actions first))
                              (error 
          "else clause is not LAST" clauses)))
                        ((cond
          -extended-clauses? first)  ;判斷是否擴(kuò)展形式
                         (make
          -if
                             (extended
          -cond-test first)
                              (list
                                (extended
          -cond-recipient first)
                                (extended
          -cond-test first))
                                (expand
          -clauses rest)))
                        (
          else
                         (make
          -if (cond-predicate first)
                                  (sequence
          ->exp (cond-actions first))
                                  (expand
          -clauses rest)))))))

          習(xí)題4.6,let如果用宏定義,類似這樣:
          (define-syntax let
            (syntax
          -rules ()
              ((_ ((x v) ) e1 e2 )
               ((
          lambda (x ) e1 e2 ) v ))))
          求值器擴(kuò)展,實(shí)現(xiàn)let->combination過程:
          (define (let? exp)
            (tagged
          -list? exp 'let))
          (define (let->combination exp)
            (let ((vars (map car (cadr exp)))
                  (vals (map cadr (cadr exp)))
                  (body (caddr exp)))
            (cons (make
          -lambda vars (list body)) vals)))
          我們做的僅僅是syntax transform,將let轉(zhuǎn)成對(duì)應(yīng)的lambda形式。

          習(xí)題4.7,這里的關(guān)鍵在于let*->netsted-lets要遞歸調(diào)用,從let*的宏定義可以看出:
          (define-syntax let*
               (syntax
          -rules()
                 ((_ ((var1 val1)) e1 )
                  (let ((var1 val1)) e1 ))
                 ((_ ((var1 val1) (var2 val2) ) e1 )
                  (let ((var1 val1))
                    (let
          * ((var2 val2) )
                      e1 )))))
          那么,let*->nested-lets可以定義為:
          (define (let*? exp)
            (tagged
          -list? exp 'let*))
          (define (let*->nested-lets exp)
               (let ((pairs (cadr exp))
                     (body (caddr exp)))
                 (
          if (null? (cdr pairs))
                     (list 
          'let pairs body)
                     (list 'let (list (car pairs)) (let*->nested-lets (list 'let* (cdr pairs) body))))))
          測(cè)試一下:
          (let* ((x 1) (y (+ x 3))) (+ x y)) =》5

          習(xí)題4.8,命名let,修改let->combination過程,判斷cadr是pair還是symbol,如果是前者,那就是一般的let,如果是symbol就是命名let語句,那么需要定義一個(gè)名為(cadr exp)的過程放在body里,注意,我們是在做語法轉(zhuǎn)換,因此,這個(gè)定義也應(yīng)該描述成符號(hào),定義一個(gè)make-define過程來生成define語句:
          (define (make-define var parameters body)
            (list 
          'define (cons var parameters) body))
          然后修改let->combination過程,如上所述:
          (define (let->combination exp)
            (
          if (symbol? (cadr exp))
                (let ((var (cadr exp))
                      (vars (map car (caddr exp)))
                      (vals (map cadr (caddr exp)))
                      (pairs (caddr exp))
                      (body (cadddr exp)))
                  (cons (make
          -lambda vars (list (make-define var vars body) body)) vals))
                (let ((vars (map car (cadr exp)))
                      (vals (map cadr (cadr exp)))
                      (body (caddr exp)))
                        (cons (make
          -lambda vars (list body)) vals))))


          習(xí)題4.1.4,原生的map過程接受的procedure,是以scheme內(nèi)在數(shù)據(jù)結(jié)構(gòu)表示的procedure,而在我們的求值器中,procedure的內(nèi)在數(shù)據(jù)結(jié)構(gòu)取決于我們,與原生的結(jié)構(gòu)不同,導(dǎo)致原生的map無法接受自制求值器的procedure,如果map也以求值器中的結(jié)構(gòu)定義,那么就沒有這個(gè)問題。因此,本質(zhì)上的困難就在于兩個(gè)求值器對(duì)procedure的數(shù)據(jù)結(jié)構(gòu)表示的不同。

          習(xí)題4.1.5,著名的圖靈停機(jī)問題,先是假設(shè)存在halts?過程可以正確地判斷任何過程p和對(duì)象a是否p對(duì)a終止,定義了try過程:
          (define (try p)
             (if (halts? p p)
                 (run-forever)
                  'halted))
          當(dāng)執(zhí)行(try try),如果這個(gè)過程可終止,那么(halts? try try)應(yīng)該返回false,也就是try過程對(duì)try不會(huì)終止,這與一開始的假設(shè)矛盾;如果這個(gè)過程將無窮運(yùn)行下去,那么(halts? try try)應(yīng)該返回true,也就是try對(duì)try終止,這也與(try try)將無窮運(yùn)行的假設(shè)矛盾。因此,可以推論出,我們不可能寫出一個(gè)過程halts?,使它能正確地判斷任何過程p和對(duì)象a是否p對(duì)a終止。

          posted @ 2008-06-01 15:51 dennis 閱讀(1038) | 評(píng)論 (0)編輯 收藏

          第一個(gè)程序:
          import java.util.ArrayList;
          import java.util.List;

          public class TailRecursionTest {
              
          public static void main(String[] args) {
                  TailRecursionTest t 
          = new TailRecursionTest();
                  
          for (int i = 0; i < 10000; i++)
                      t.a(
          0);
              }

              
          public void a(int j) {
                  j
          ++;
                  List list 
          = new ArrayList<Integer>(100000);
                  
          // 對(duì)list進(jìn)行處理
              }
          }
              沒啥特殊的,僅僅是為了測(cè)試,我們將a方法調(diào)用10000次,a方法創(chuàng)建一個(gè)有100000個(gè)元素的list的局部變量。
          第二個(gè)程序:
          import java.util.ArrayList;
          import java.util.List;

          public class TailRecursionTest2 {
              
          public static void main(String[] args) {
                  TailRecursionTest2 t 
          = new TailRecursionTest2();
                  t.a(
          0);
              }

              
          public void a(int j) {
                  System.out.println(j);
                  j
          ++;
                  
          if (j == 10000)
                      
          return;
                  List list 
          = new ArrayList<Integer>(100000);
                  
          // 對(duì)list進(jìn)行處理
                  a(j);
              }
          }

              也沒啥特殊的,就是將循環(huán)換成了遞歸,a方法做的事情沒變。兩個(gè)都跑一下,程序1順利結(jié)束,程序2出問題了,啥問題?如下:
          161
          162
          163
          164
          165
          Exception in thread 
          "main" java.lang.OutOfMemoryError: Java heap space
              at java.util.ArrayList.
          <init>(Unknown Source)
              at TailRecursionTest2.a(TailRecursionTest2.java:
          17)
              at TailRecursionTest2.a(TailRecursionTest2.java:
          20)
              at TailRecursionTest2.a(TailRecursionTest2.java:
          20)
              at TailRecursionTest2.a(TailRecursionTest2.java:
          20)
              at TailRecursionTest2.a(TailRecursionTest2.java:
          20)
             我倒,才運(yùn)行166次了,heap就滿了。問題在哪呢?oh,yep,你肯定想到了,是不是重復(fù)創(chuàng)建list這個(gè)大集合引起的呢?它不是局部變量嗎?怎么也會(huì)溢出?是的,list是局部變量,在a的方法棧里引用著,指向heap上的大對(duì)象,更關(guān)鍵的問題在于,java是沒有尾遞歸優(yōu)化的,遞歸方法是不會(huì)使用同一個(gè)棧幀,每一次遞歸調(diào)用,都將壓入新的棧幀,并且這個(gè)棧幀上又new了一個(gè)list變量,引用著heap上新的一個(gè)大集合。隨著棧深度的增加,jvm里維持著一條長(zhǎng)長(zhǎng)的方法調(diào)用軌跡以便你能回來,在方法沒有返回之前,這些list變量一直被各自的棧幀引用著,不能被GC,你說,能不OOM嗎?
              也許,你想到了個(gè)補(bǔ)救方法來挽救程序2,就是每次在處理完list后,我把它設(shè)置為null,不讓棧幀繼續(xù)引用著它,咱編寫對(duì)gc友好的代碼,這不就行了,試試:
          import java.util.ArrayList;
          import java.util.List;

          public class TailRecursionTest2 {
              
          public static void main(String[] args) {
                  TailRecursionTest2 t 
          = new TailRecursionTest2();
                  t.a(
          0);
              }

              
          public void a(int j) {
                  System.out.println(j);
                  j
          ++;
                  
          if (j == 10000)
                      
          return;
                  List list 
          = new ArrayList<Integer>(100000);
                  
          // 對(duì)list進(jìn)行處理
                  list = null;  //gc友好
                  a(j);
              }
          }
              得意洋洋,我跑一下看看,這次跑到4000多次,但是:
          ......
          4289

          4290
          4291
          4292
          java.lang.StackOverflowError
              at sun.nio.cs.ext.DoubleByteEncoder.encodeArrayLoop(Unknown Source)
              at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source)
              at java.nio.charset.CharsetEncoder.encode(Unknown Source)
              沒辦法啊,人家sun的jdk就是不支持尾遞歸優(yōu)化,很不給你面子的棧溢出了。ibm的jdk據(jù)說支持尾遞歸優(yōu)化,上面這個(gè)程序在ibm的jdk上可能可以正常結(jié)束,未經(jīng)測(cè)試。

          總結(jié):在java里,遞歸最好咱還是別用,老老實(shí)實(shí)地while、for;就算遞歸了,最好遞歸方法不要new太大的對(duì)象,除非你能確定遞歸的深度不是那么大。

          posted @ 2008-05-31 17:25 dennis 閱讀(2153) | 評(píng)論 (4)編輯 收藏

               摘要: 6到11章  閱讀全文

          posted @ 2008-05-28 23:07 dennis 閱讀(4086) | 評(píng)論 (0)編輯 收藏

               摘要: 《Logic Programming with Prolog》的讀書筆記,書其實(shí)一般,內(nèi)容都是基礎(chǔ)性的語法和BIPs介紹,比較失望的是對(duì)Prolog的應(yīng)用涉及很少。  閱讀全文

          posted @ 2008-05-28 23:05 dennis 閱讀(4064) | 評(píng)論 (0)編輯 收藏

              去年申請(qǐng)的rubyeye.net,年初到期了,忘了去續(xù)費(fèi)。今天又去申請(qǐng)了兩個(gè):rubyeye.net和zhuangxiaodan.cn。cn域名就是便宜,一塊錢一個(gè):)。rubyeye.net申請(qǐng)了兩年,以免再次忘記續(xù)費(fèi),總計(jì)花費(fèi)98塊,還是挺劃算的。兩個(gè)都設(shè)置了url轉(zhuǎn)發(fā),現(xiàn)在可以通過 www.zhuangxiaodan.cn和www.rubyeye.net訪問我的blog啦。貌似rubyeye.net的還沒生效,明天應(yīng)該可以了。前天同事推薦了個(gè)ror的虛擬主機(jī),一年200塊,300M空間,10G/月的流量,挺實(shí)惠,就想著搞個(gè)typo弄上去,搬家過去??苫叵肫鹎懊鎺状伟峒业慕?jīng)歷,心里立馬打退堂鼓,盡管可以去搞個(gè)腳本導(dǎo)入這些日志,也是夠麻煩的,我還得去看下typo的數(shù)據(jù)表結(jié)構(gòu)。看來還是老老實(shí)實(shí)呆在blogjava為妙。

          posted @ 2008-05-27 16:43 dennis 閱讀(667) | 評(píng)論 (3)編輯 收藏

              今天整理代碼,發(fā)現(xiàn)一個(gè)去年寫的簡(jiǎn)單的工作流引擎,基于petri網(wǎng)(參考這里的筆記),實(shí)現(xiàn)了順序、并行、循環(huán)和選擇四種路由,資源也實(shí)現(xiàn)了人工驅(qū)動(dòng)和定時(shí)、延遲時(shí)間驅(qū)動(dòng);目前只實(shí)現(xiàn)了將工作流數(shù)據(jù)保存在內(nèi)存的版本,然后就換工作,折騰著就忘了這個(gè)事兒,本來是計(jì)劃加入數(shù)據(jù)庫(kù)存儲(chǔ)的。盡管只是個(gè)toy,可能對(duì)工作流感興趣,或者想自己實(shí)現(xiàn)一個(gè)玩玩的朋友有參考價(jià)值,放到了google code上,svn地址:
           http://insectworkflow.googlecode.com/svn/trunk/

              源碼中有在example包下給了個(gè)請(qǐng)假的例子,流程定義文件就是processes包下的leave.xml,實(shí)現(xiàn)大概是這么個(gè)流程:
          填寫假單-》提交假單-and-split節(jié)點(diǎn)-》項(xiàng)目經(jīng)理審批-》and-join節(jié)點(diǎn)-》結(jié)束
                                                               -》部門經(jīng)理審批-》

          其中項(xiàng)目經(jīng)理審批和部門經(jīng)理審批是并行路由。xml配置大概這樣:
          <node type="and-split" name="and-split" id="2">
                  
          <inputs>
                      
          <place id="3" />
                  
          </inputs>
                  
          <outputs>
                      
          <place id="4" />
                      
          <place id="5" />
                  
          </outputs>
              
          </node>
              
          <node name="dept_manager_confirm" id="3">
                  
          <resource class="com.google.code.insect.workflow.impl.Group" id="2"
                      name
          ="dept_manager">
                  
          </resource>
                  
          <conditions type="and">
                      
          <condition
                          
          class="com.google.code.insect.workflow.impl.NullHandler" value="false"
                          variable-name
          ="LeaveInfo" />
                  
          </conditions>
                  
          <handler
                      
          class="com.google.code.insect.workflow.example.leave.SendRemindHandler" />
                  
          <inputs>
                      
          <place id="4" />
                  
          </inputs>
                  
          <outputs>
                      
          <place id="6" />
                  
          </outputs>
              
          </node>
              
          <node name="project_manager_confirm" id="4">
                  
          <resource class="com.google.code.insect.workflow.impl.Group" id="3"
                      name
          ="project_manager">
                  
          </resource>
                  
          <conditions type="and">
                      
          <condition
                          
          class="com.google.code.insect.workflow.impl.NullHandler" value="false"
                          variable-name
          ="LeaveInfo" />
                  
          </conditions>
                  
          <handler
                      
          class="com.google.code.insect.workflow.example.leave.SendRemindHandler" />
                  
          <inputs>
                      
          <place id="5" />
                  
          </inputs>
                  
          <outputs>
                      
          <place id="7" />
                  
          </outputs>
              
          </node>
              
          <node type="and-join" name="and-join" id="5">
                  
          <handler
                      
          class="com.google.code.insect.workflow.example.leave.ResultHandler" />
                  
          <inputs>
                      
          <place id="6" />
                      
          <place id="7"></place>
                  
          </inputs>
                  
          <outputs>
                      
          <place id="8" />
                  
          </outputs>
              
          </node>

              其中的place就是各個(gè)Transition的輸入或者輸出庫(kù)所,所謂node其實(shí)就是變遷(transition),每個(gè)變遷對(duì)應(yīng)一個(gè)handler,執(zhí)行具體的業(yè)務(wù)操作,比如這里的com.google.code.insect.workflow.example.leave.SendRemindHandler 用于發(fā)送提醒消息給經(jīng)理們。

              具體調(diào)用和工作項(xiàng)的人工觸發(fā):

          //初始化工作流管理器
          WorkFlowManager wm = new BasicWorkflowManager();
          wm.setConfiguration(
          new DefaultConfiguration());

          //啟動(dòng)一個(gè)案例
          Token token = wm.startWorkFlow("leave");
          token.setAttribute(
          "LeaveInfo", leaveInfo);

          //提交假單
          wm.doAction(token.getId(), this.dennis, "給領(lǐng)導(dǎo)發(fā)送消息:"
                          
          + leaveInfo.getStaff_name() + "申請(qǐng)請(qǐng)假,請(qǐng)批準(zhǔn)!");
          //將token的id傳遞給后續(xù)節(jié)點(diǎn)做處理。。token的id就是案例id
              processes包下面的流程定義文件和test包下的TestUnit,分別測(cè)試了四種路由和定時(shí)、延時(shí)觸發(fā),有興趣的可以看一下。

          posted @ 2008-05-21 15:09 dennis 閱讀(2151) | 評(píng)論 (0)編輯 收藏

              轉(zhuǎn)眼間,來廣州快半年了,感覺還不錯(cuò)。廣州如死魚所說的那樣,是個(gè)包容并且很有活力的城市,習(xí)慣了周末煲湯,去天河公園跑跑步,這生活還是挺舒適的,除了比較潮的天氣。
              最近跟公司鬧了點(diǎn)不愉快,在轉(zhuǎn)正時(shí)間上,其實(shí)不是多大的事,只是心里不舒服罷了,干起活來也沒什么激情了,呵呵。當(dāng)然,手頭的工作咱還是要高效率地完成,做完兩個(gè)游戲后,現(xiàn)在轉(zhuǎn)到棋牌類,棋牌類游戲核心就兩個(gè)算法:隨機(jī)發(fā)牌和出牌判斷。隨機(jī)發(fā)牌算法,學(xué)習(xí)了云風(fēng)的blog上提到的方法,感覺還可以接受;出牌規(guī)則判斷,倒是沒想象中的復(fù)雜,建立牌型的OO模型,一切都很簡(jiǎn)單了。另外一個(gè)發(fā)現(xiàn),用jdk6跑jruby1.1.1,比用jdk5跑效率(包括內(nèi)存和CPU)好上很多,例如我們一個(gè)游戲進(jìn)程,在使用jdk5時(shí),CPU穩(wěn)定在15%,內(nèi)存85M,而改用jdk6后,cpu降到了%5以下,內(nèi)存也縮減到70多M。
              搞完了之后,時(shí)間有點(diǎn)空閑,就想學(xué)點(diǎn)新東西,最后選擇了Prolog。Yep,非常地有趣,真正的聲明式編程語言。Prolog本質(zhì)上就是兩個(gè)東西:規(guī)則和事實(shí),由事實(shí)和規(guī)則出發(fā),Prolog的推理系統(tǒng)將回答你的查詢(query)。有點(diǎn)類似現(xiàn)在流行中的規(guī)則引擎的概念,在對(duì)效率不是很考慮的場(chǎng)景中,嵌入一個(gè)Prolog引擎做規(guī)則引擎完全是可以的,java中有個(gè)tuProlog項(xiàng)目,可以關(guān)注一下。然后就是一直在讀的sicp,延時(shí)求值模擬無窮級(jí)數(shù)實(shí)在是相當(dāng)?shù)豤ool,大開眼界。這兩天一直在理解continuation這個(gè)概念,小有所得。一個(gè)表達(dá)式的求值可以分為兩個(gè)階段:“What to evaluate?”和“What to do with the value”,“What to do with the value”就是計(jì)算的Continuation。例如,scheme求值下列表達(dá)式:
          (if (null? x) (quote ()) (cdr x))
          先求值表達(dá)式(null? x),(null? x)就是“What to evaluate”,當(dāng)(null? x)求值后,需要根據(jù)這個(gè)值來決定是執(zhí)行(quote ())還是(cdr x),這個(gè)根據(jù)值來決定的過程就是Continuation。如果在每次函數(shù)調(diào)用時(shí),同時(shí)傳入當(dāng)前的continuation,那么就完全可以不要堆棧。call/cc就提供了這樣的一個(gè)語法糖,call/cc全稱就是call-with-current-continuation,要求參數(shù)是一個(gè)過程,調(diào)用這個(gè)過程,并且向這個(gè)過程傳入當(dāng)前的continuation(一般稱為k,kont,或者Ruby中一般是c,cont),這就是call/cc為我們做的。call/cc是實(shí)現(xiàn)Continuation的方式之一,coroutine/fiber/yield也是實(shí)現(xiàn)continuation的方式?!禩he Scheme Programming Language》給出的輕量級(jí)進(jìn)程機(jī)制的例子比較有趣:
          (define lwp-list '())
          (define (lwp thunk)
            (set! lwp
          -list (append lwp-list (list thunk))))
          (define start
            (
          lambda()
              (let ((p (car lwp
          -list)))
                (set! lwp
          -list (cdr lwp-list))
                (p))))
          (define pause
            (
          lambda()
              (callcc (
          lambda(k) 
                         (lwp (
          lambda () (k #f)))
                         (start)))))
          (lwp (
          lambda () (let f () (display "h") (pause) (f))))
          (lwp (
          lambda () (let f () (display "e") (pause) (f))))
          (lwp (
          lambda () (let f () (display "y") (pause) (f))))
          (lwp (
          lambda () (let f () (display "!") (pause) (f))))
          (lwp (
          lambda () (let f () (newline) (pause) (f))))
          (start)
          實(shí)現(xiàn)了代碼級(jí)的進(jìn)程調(diào)度。

          posted @ 2008-05-21 11:45 dennis 閱讀(1961) | 評(píng)論 (4)編輯 收藏

          僅列出標(biāo)題
          共56頁: First 上一頁 25 26 27 28 29 30 31 32 33 下一頁 Last 
          主站蜘蛛池模板: 和硕县| 耒阳市| 黎平县| 永平县| 黎城县| 天祝| 东海县| 达日县| 额尔古纳市| 三明市| 广汉市| 精河县| 祁阳县| 盐边县| 叶城县| 镇原县| 屯门区| 沁源县| 陇西县| 凤翔县| 潞西市| 自治县| 济南市| 通辽市| 尖扎县| 都江堰市| 宜阳县| 宜川县| 南雄市| 来安县| 北京市| 珠海市| 中西区| 比如县| 南城县| 连州市| 泾源县| 阿克| 高淳县| 云安县| 夹江县|