莊周夢蝶

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

             ets表的底層是由哈希表實現的,不過ordered_set例外,它是由平衡二叉樹實現的。 所以不管是插入還是查找,set的效率要比ordered_set高.采用set還是ordered_set取決于你的需求,當你需要一個有序的集合時,顯然應當采用ordered_set模式。

          duplicate_bag要比bag的效率要高, 因為bag要和原來的記錄比較是否有相同的記錄已經插入. 如果數據量很大,相同的記錄越多,bag的效率就越差.

          一張ets表是由創建它的進程所擁有, 當此進程調用ets:delete或者進程終止的時候, ets表就會被刪除.

          一般情況下, 插入一個元組到一張ets表中, 所有代表這個元組的結構都會被從process的堆棧中,復制到ets表中; 當查找一條記錄時, 結果tuple從ets表中復制到進程的堆棧中。

          但是large binaries卻不是這樣! 它們被存入自已所擁有的off-heap area中。這個區域可以被多個process,ets表,和binaries所共享。它由引用計數的垃圾回收策略管理, 這個策略會跟蹤到底有多少個process/ets表/binaries引用了這個large binaries. 如果引用數為0的話, 此大型二進制數據就會被垃圾回收掉.

          看起來很復雜, 實際結論就是: 兩進程間發送包含大型binary數據的消息其實費用很低, 往ets表插入binary類型元組也很劃算。我們應該盡可能采用binaries來實現字符串或無類型的大數據塊.

          posted @ 2007-09-27 16:33 dennis 閱讀(2195) | 評論 (2)編輯 收藏

          Erlang用于操縱文件I/O的模塊有:
          file模塊:打開、讀、寫、關閉文件已經操作目錄的方法基本都在這里

          filename模塊:提供平臺獨立方式用于操縱文件名

          filelib模塊:file模塊的擴展,提供了更多的實用工具,在file模塊基礎上構建

          io模塊:一系列用于操作打開的文件的方法,解析格式、格式化輸出等等。

          1.打開文件:
          {ok,F}=file:open("data1.dat",read). %讀模式打開
          {ok,F}=file:open("data1.dat",write). %寫模式
          {ok,F}=file:open("data1.dat",[read,write]). %讀、寫、二進制模式

          支持的所有模式參見文檔。

          2.讀取:
          (1)如果以一個Erlang term的方式讀取,采用:
          io:read(F,'').
          其中第二個參數是提示符,用于在標準輸入時作為提示。
          這個方法有一個變形read/3
          read(IoDevice, Prompt, StartLine)
          第三個參數用于指定開始行數。

          (2)如果是按字節讀取,文件必須按raw模式打開采用:
          {ok, Data}=file:read(F,100).

          (3)按行讀取:
          io:get_line(F, '').

          (4)讀取整個文件的內容:
          {ok,Binary}=file:read_file("data1.dat").
          注意返回的是一個binary類型

          (5)隨機讀取:
          {ok,Binary}=file:pread(F, 22, 46).

          其中第二個參數是開始位置,第三個參數是讀取的長度,返回的也是binary類型。

          3.寫入文件:
          (1)采用io:format/3方法:
          {ok, S} = file:open("test2.dat", write).
          io:format(S, "~s~n", ["Hello readers"]).
          io:format(S, "~w~n", [123]).

          其中的~開頭的字符是一個個格式化命令,比如常見的:
          ~c   anscii碼
          ~f   浮點數
          ~s   字符串
          ~w   Erlang term
          ~p   與~w類似,不過當多行時將自動換行
          ~n   顯然,換行符

          (2)寫入整個文件:
          file:write_file(File, IO)

          其中IO可以為list、integer或者binary類型

          (3)隨機寫入:
          file:pwrite(F, 10, <<"new">>)

          4.關閉文件:
          file:close(F).

          5.目錄操作:
          都是linux命令風格的操作,
          cd("/home/dennis/").  %進入目錄
          file:list_dir(".").   %列出當前目錄文件
          file:make_dir("test").  %創建test目錄
          file:del_dir("test").   %刪除test目錄

          6.獲取文件信息,比如文件大小,最后修改時間等等。調用file:read_file_info/1方法,該方法返回一個file_info記錄類型,里面擁有文件的具體信息,比如type、size等。
          {ok, Facts} =file:read_file_info(File).
          io:format("~s~n",{Facts#file_info.type, Facts#file_info.size}).

          7.復制和刪除文件:
          file:copy(Source, Destination).
          file:delete(File).

              這個筆記僅僅記錄了一些常用到的方法,一些高級的工具方法并沒有涉及,具體參考Erlang的文檔。




          posted @ 2007-09-27 16:03 dennis 閱讀(7950) | 評論 (2)編輯 收藏

              讀完ruby hacking guide第6章,徹底總結下:
          1.在Ruby中,類也是一個對象,因此有實例變量。類的實例變量、類變量、常量都是存儲在RClass struct的iv_tbl中,
          struct RClass {
              struct RBasic basic;
              struct st_table *iv_tbl;
              struct st_table *m_tbl;
              VALUE super;
          };
          iv_tbl的類型是st_table,我在這里用java實現了一下。

          2.用戶自定義類的對象(ruby層次聲明的類的對象)的實例變量存儲在RObject struct的iv_tbl中,
          struct RObject {
            struct RBasic basic;
            struct st_table *iv_tbl;
           };
          調用方法,本質上是一個查表操作。buildin的幾個類,比如String、Array、Hash等(在c層次上實現的類),它們的結構并沒有iv_table,這是從節省內存空間的角度考慮,它們的實例變量存儲在一張全局的st_table中。這張表比較特別,其中的每一個對應的值又是一個st_table,也就是一個“二元結構”,第一層結構是類名與實例變量表的映射,第二層才是實例變量名與實際值的映射。

          3.全局變量存儲在一張全局的st_table中,這個表的鍵就是變量名ID,由于全局變量允許通過alias來設置別名,因此這張全局表中真正存儲的是下面這個struct

          334 struct global_entry {
          335 struct global_variable *var;
          336 ID id;
          337 };

          324 struct global_variable {
          325 int counter; /* 引用計數 */
          326 void *data; /* 變量值 */
          327 VALUE (*getter)(); /* 取值函數 */
          328 void (*setter)(); /* 設置函數 */
          329 void (*marker)(); /* 標記函數 */
          330 int block_trace;
          331 struct trace_var *trace;
          332 };
          (variable.c)

          當不同變量名(通過別名聲明)指向的是同一個全局變量,其實它們指向的是同一個struct global_variable。


          posted @ 2007-09-20 16:17 dennis 閱讀(667) | 評論 (0)編輯 收藏

              今天向公司提出辭職了,考慮這么久,還是決定辭職。我不想浪費大半年時間做維護,大部分時間無所事事,這是我不能接受的。我需要更多的項目經歷來鍛煉自己。在公司這一年,學到的不少,無論從做人還是技術上都有所感悟,接下來確定去廈門,未來將怎么樣?還是充滿希望和憧憬,希望好運吧。

          posted @ 2007-09-20 12:48 dennis 閱讀(572) | 評論 (4)編輯 收藏

               摘要:     update1:添加了remove,removeAll()方法以及getSize()方法     update2:添加了keySet()方法用于迭代       update3:經過測試,StTable類在存儲Integer類型key時,put的速度比HashMap快了接近3倍,而...  閱讀全文

          posted @ 2007-09-18 19:28 dennis 閱讀(1358) | 評論 (0)編輯 收藏

              dreamhead老大曾經討論過這個問題,尋找一種可移植的方式來判斷棧的增長方向,見《棧的增長方向》。今天在讀Ruby hacking guide第5章,介紹alloca函數的部分,提到ruby實現的C語言版本的alloca.c,讀了下代碼,發現這里倒是實現了一個很漂亮的函數用于實現判斷棧的增長方向,利用了局部static變量,與dreamhead老大的想法其實是一致的。
          #include<stdio.h>
          static void find_stack_direction(void);
          static int stack_dir;
          int main(void)
          {
            find_stack_direction();
            
          if(stack_dir==1)
               puts(
          "stack grew upward");
            
          else
               puts(
          "stack grew downward");
            
          return 0;
          }
          static void find_stack_direction (void)
          {
            
          static char   *addr = NULL;   /* address of first
                                             `dummy', once known 
          */
            auto 
          char     dummy;          /* to get stack address */

            
          if (addr == NULL)
              {                           
          /* initial entry */
                addr 
          = &dummy;

                find_stack_direction ();  
          /* recurse once */
              }
            
          else                          /* second entry */
              
          if (&dummy > addr)
                stack_dir 
          = 1;            /* stack grew upward */
              
          else
                stack_dir 
          = -1;           /* stack grew downward */
          }

          posted @ 2007-09-17 16:16 dennis 閱讀(1138) | 評論 (0)編輯 收藏

              ReentrantLock是jdk5引入的新的鎖機制,它與內部鎖(synchronize) 相同的并發性和內存語義,比如可重入加鎖語義。在中等或者更高負荷下,ReentrantLock有更好的性能,并且擁有可輪詢和可定時的請求鎖等高級功能。這個程序簡單對比了ReentrantLock公平鎖、ReentrantLock非公平鎖以及內部鎖的性能,從結果上看,非公平的ReentrantLock表現最好。內部鎖也僅僅是實現統計意義上的公平,結果也比公平的ReentrantLock好上很多。這個程序僅僅是計數,啟動N個線程,對同一個Counter進行遞增,顯然,這個遞增操作需要同步以保證原子性,采用不同的鎖來實現同步,然后查看結果。
          Counter接口:
          package net.rubyeye.concurrency.chapter13;

          public interface Counter {
              
          public long getValue();

              
          public void increment();

          }

          然后,首先使用我們熟悉的synchronize來實現同步:
          package net.rubyeye.concurrency.chapter13;

          public class SynchronizeBenchmark implements Counter {
              
          private long count = 0;

              
          public long getValue() {
                  
          return count;
              }

              
          public synchronized void increment() {
                  count
          ++;
              }
          }

          采用ReentrantLock的版本,切記要在finally中釋放鎖,這是與synchronize使用方式最大的不同,內部鎖jvm會自動幫你釋放鎖,而ReentrantLock需要你自己來處理。
          package net.rubyeye.concurrency.chapter13;

          import java.util.concurrent.locks.Lock;
          import java.util.concurrent.locks.ReentrantLock;

          public class ReentrantLockBeanchmark implements Counter {

              
          private volatile long count = 0;

              
          private Lock lock;

              
          public ReentrantLockBeanchmark() {
                  
          // 使用非公平鎖,true就是公平鎖
                  lock = new ReentrantLock(false);
              }

              
          public long getValue() {
                  
          // TODO Auto-generated method stub
                  return count;
              }

              
          public void increment() {
                  lock.lock();
                  
          try {
                      count
          ++;
                  } 
          finally {
                      lock.unlock();
                  }
              }

          }

              寫一個測試程序,使用CyclicBarrier來等待所有任務線程創建完畢以及所有任務線程計算完成,清單如下:
          package net.rubyeye.concurrency.chapter13;

          import java.util.concurrent.CyclicBarrier;

          public class BenchmarkTest {
              
          private Counter counter;

              
          private CyclicBarrier barrier;

              
          private int threadNum;

              
          public BenchmarkTest(Counter counter, int threadNum) {
                  
          this.counter = counter;
                  barrier 
          = new CyclicBarrier(threadNum + 1); //關卡計數=線程數+1
                  this.threadNum = threadNum;
              }

              
          public static void main(String args[]) {
                  
          new BenchmarkTest(new SynchronizeBenchmark(), 5000).test();
                 
          //new BenchmarkTest(new ReentrantLockBeanchmark(), 5000).test();
                  //new BenchmarkTest(new ReentrantLockBeanchmark(), 5000).test();   
              }

              
          public void test() {
                  
          try {
                      
          for (int i = 0; i < threadNum; i++) {
                          
          new TestThread(counter).start();
                      }
                     
          long start = System.currentTimeMillis();
                      barrier.await(); // 等待所有任務線程創建
                      barrier.await(); // 等待所有任務計算完成
                      long end = System.currentTimeMillis();
                      System.out.println(
          "count value:" + counter.getValue());
                      System.out.println(
          "花費時間:" + (end - start) + "毫秒");
                  } 
          catch (Exception e) {
                      
          throw new RuntimeException(e);
                  }
              }

              
          class TestThread extends Thread {
                  
          private Counter counter;

                  
          public TestThread(final Counter counter) {
                      
          this.counter = counter;
                  }

                  
          public void run() {
                      
          try {
                          barrier.await();
                          
          for (int i = 0; i < 100; i++)
                              counter.increment();
                          barrier.await();
                      } 
          catch (Exception e) {
                          
          throw new RuntimeException(e);
                      }
                  }
              }
          }

          分別測試一下,

          將啟動的線程數限定為500,結果為:
          公平ReentrantLock:      210 毫秒
          非公平ReentrantLock :   39  毫秒
          內部鎖:                          39 毫秒

          將啟動的線程數限定為1000,結果為:
          公平ReentrantLock:      640 毫秒
          非公平ReentrantLock :   81 毫秒
          內部鎖:                           60 毫秒

          線程數不變,test方法中的循環增加到1000次,結果為:
          公平ReentrantLock:      16715 毫秒
          非公平ReentrantLock :   168 毫秒
          內部鎖:                           639  毫秒

          將啟動的線程數增加到2000,結果為:
          公平ReentrantLock:      1100 毫秒
          非公平ReentrantLock:   125 毫秒
          內部鎖:                           130 毫秒

          將啟動的線程數增加到3000,結果為:
          公平ReentrantLock:      2461 毫秒
          非公平ReentrantLock:   254 毫秒
          內部鎖:                           307 毫秒

          啟動5000個線程,結果如下:
          公平ReentrantLock:      6154  毫秒
          非公平ReentrantLock:   623   毫秒
          內部鎖:                           720 毫秒

          非公平ReentrantLock和內部鎖的差距,在jdk6上應該縮小了,據說jdk6的內部鎖機制進行了調整。

          posted @ 2007-09-14 17:15 dennis 閱讀(8129) | 評論 (2)編輯 收藏

              Ruby語言中的String是mutable的,不像java、C#中的String是immutable的。比如
                 str1="abc"
                 str2="abc"
          在java中,對于字面量的字符串,jvm內部維持一張表,因此如果在java中,str1和str2是同一個String對象。而在Ruby中,str1和str2是完全不同的對象。同樣,在java中對于String對象的操作都將產生一個新的對象,而Ruby則是操縱同一個對象,比如:
                 str="abc"
                 str.concat("cdf")
          此時str就是"abccdf"。Ruby對String是怎么處理的呢?我們只談談c ruby中的實現,有興趣的先看看這篇文章《管窺Ruby——對象基礎》。在ruby.h中我們可以看到String對象的結構,Ruby中的對象(包括類也是對象)都是一個一個的struct,String也不能例外:
          struct RString {
              struct RBasic basic;
              long len;
              char *ptr;
              union {
                long capa;
                VALUE shared;
              } aux;
          };
          //ruby.h

              顯然,len是String的長度;ptr是一個char類型的指針,指向實際的字符串;然后是一個聯合,這個稍后再說。如果你看看ruby.h可以發現,幾乎所有定義的對象結構都有一個struct RBasic。顯然,struct RBasic包含由所有對象結構體共享的一些重要信息的。看看RBasic:

          struct RBasic {
           unsigned long flags;
           VALUE klass;
          };
          其中的flags是一個多用途的標記,大多數情況下用于記錄結構體的類型,ruby.h中預定義了一些列的宏,比如T_STRING(表示struct RString),T_ARRAY(表示struct RArray)等。Klass是一個VALUE類型,VALUE也是unsigned long,可以地將它當成指針(一個指針4字節,綽綽有余了),它指向的是一個Ruby對象,這里以后再深入。
              那么聯合aux中的capa和shared是干什么用的呢?因為Ruby的String是可變的,可變意味著len可以改變,我們需要每次都根據len的變換來增減內存(使用c中的realloc()函數),這顯然是一個很大的開銷,解決辦法就是預留一定的空間,ptr指向的內存大小略大于len,這樣就不需要頻繁調用realloc了,aux.capa就是一個長度,包含額外的內存大小。那么aux.shared是干什么的呢?這是一個VALUE類型,說明它是指向某個對象。aux.shared其實是用于加快字符串的創建速度,在一個循環中:
          while true do  # 無限重復
          a = "str" # 以“str”為內容創建字符串,賦值給a
          a.concat("ing") # 為a所指向的對象添加“ing”
          p(a) # 顯示“string”
          end
          每次都重新創建一個"str"對象,內部就是重復創建一個char[],這是相當奢侈,aux.shared就是用于共享char[],
          以字面量創建的字符串會共享一個char[],當要發生變化時,將字符串復制到一個非共享的內存中,變化針對這
          個新拷貝進行,這就是所謂的“copy-on-write"技術。解釋了String的內部構造,貌似還沒有介紹String是怎么
          實現mutable,我們寫一個Ruby擴展測試下,我們想寫這樣一個Ruby類:
          class Test
          def test
          str="str"
          str.concat("ing")
          end
          end
          對應的c語言代碼就是:
          #include<stdio.h>
          #include 
          "ruby.h"

          static VALUE t_test(VALUE self)
          {
            VALUE str;
            str
          =rb_str_new2("str");
            printf(
          "before concat: str:%p, str.aux.shared:%p, str.ptr:%s"n",str,
                 (RSTRING(str)->aux).shared,RSTRING(str)->ptr);
            rb_str_cat2(str,
          "ing");
            printf(
          "after concat: str:%p, str.aux.shared:%p, str.ptr:%s"n",
                 str,(RSTRING(str)->aux).shared,RSTRING(str)->ptr);
            
          return self;
          }
          VALUE cTest;
          void Init_string_hack(){
            cTest
          =rb_define_class("Test",rb_cObject);
            rb_define_method(cTest,
          "test",t_test,0);

          }
          //string_hack.c
             rb_define_class函數定義了一個類Test,rb_define_method將t_test方法以test的名稱添加到Test類。在
          t_test中,通過rb_str_new2每次生成一個RString結構,然后通過rb_str_cat2將str與"ing"連接起來,添加
          了一些打印用于跟蹤。利用mkmf產生Makefile,寫一個extconf.rb
          require 'mkmf'
          create_makefile("string_hack");
          執行ruby extconf.rb,將產生一個Makefile,執行make,生成一個string_hack.so的鏈接庫。擴展寫完了,通過
          ruby調用:
          require 'string_hack"
          t=Test.new
          (1..3).each{|i| t.test}
          輸出:
          before concat: str:0x40098a40, str.aux.shared:0x3, str.ptr:str
          after concat: str:0x40098a40, str.aux.shared:0x8, str.ptr:string
          before concat: str:0x40098a2c, str.aux.shared:0x3, str.ptr:str
          after concat: str:0x40098a2c, str.aux.shared:0x8, str.ptr:string
          before concat: str:0x40098a18, str.aux.shared:0x3, str.ptr:str
          after concat: str:0x40098a18, str.aux.shared:0x8, str.ptr:string
          從結果可以看出,在str concat之前之后,str指向的位置沒有改變,改變的僅僅是str中ptr指向的字符串的值
          ,看看rb_str_cat2函數的實現就一目了然了:
          VALUE rb_str_cat(str, ptr, len)
              VALUE str;
              const char *ptr;
              long len;
          {
              if (len < 0) {
                  rb_raise(rb_eArgError, "negative string size (or size too big)");
              }
              if (FL_TEST(str, STR_ASSOC)) {
                  rb_str_modify(str);
                  REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len);
                  memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len);
                  RSTRING(str)->len += len;
                  RSTRING(str)->ptr[RSTRING(str)->len] = '"0'; /* sentinel */
                  return str;
              }
              return rb_str_buf_cat(str, ptr, len);
          }
          VALUE rb_str_cat2(str, ptr)
              VALUE str;
              const char *ptr;
          {
              return rb_str_cat(str, ptr, strlen(ptr));
          }
          //string.c



          posted @ 2007-09-12 09:43 dennis 閱讀(1935) | 評論 (0)編輯 收藏

              在javaeye上看到的轉貼,原始出處不知道在何處了。50本世界名著一句話總結,粗粗掠過,自己也就看了其中的15本左右,而給我留下最深印象的仍然是卡夫卡的《變形記》,仍然記的第一次閱讀時心靈的悸動,乃至后來看村上的《海邊的卡夫卡》,隱喻中的現實真實而殘酷。

              1.神要是公然去跟人作對,那是任何人都難以對付的。(《荷馬史詩》)

          2.生存還是毀滅,這是一個值得思考的問題。(《哈姆霄特》)

          3.善良人在追求中縱然迷惘,卻終將意識到有一條正途。(《浮士德》)

          4.認識自己的無知是認識世界的最可靠的方法。(《隨筆集》)

          5.你以為我貧窮、相貌平平就沒有感情嗎?我向你發誓,如果上帝賦予我財富和美貌,我會讓你無法離開我,就像我現在無法離開你一樣。雖然上帝沒有這么做,可我們在精神上依然是平等的。(《簡-愛》)

          6.大人都學壞了,上帝正考驗他們呢,你還沒有受考驗,你應當照著孩子的想法生活。(《童年》)

          7,你越沒有心肝,就越高升得快,你毫不留情地打擊人家,人家就怕你。只能把男男女女當作驛馬,把它們騎得筋疲力盡,到了站上丟下來,這樣你就能達到欲望的最高峰。(《高老頭》)

          8.我只想證明一件事,就是,那時魔鬼引誘我,后來又告訴我,說我沒有權利走那條路,因為我不過是個虱子,和所有其余的人一樣。(《罪與罰》)

          9.你瞧,桑丘?潘沙朋友,那邊出現了三十多個大得出奇的巨人。(《堂-吉訶德》)

          10.我并不愿意你受的苦比我受的還大,希斯克利夫。我只愿我們永遠不分離:如果我有一句話使你今后難過,想想我在地下也感到一樣的難過,看在我自己的份上,饒恕我吧!(《呼嘯山莊》)

          11.幸福的家庭是相同的,不幸的家庭各有各的不同。(《安娜-卡列尼娜》)

          12.唉,奴隸般的意大利,你哀痛之逆旅,你這暴風雨中沒有舵手的孤舟,你不再是各省的主婦,而是妓院!(《神曲》)

          13.將感情埋藏得太深有時是件壞事。如果一個女人掩飾了對自己所愛的男子的感情,她也許就失去了得到他的機會。(《傲慢與偏見》)

          14.鐘聲又鳴響了……一聲又一聲,靜謐而安詳,即使在女人做新娘的那個好月份里,鐘聲里也總帶有秋天的味道。(《喧囂與騷動》)

          15.一個人并不是生來要被打敗的,你盡可以把他消滅掉,可就是打不敗他。(《老人與海》)

          16.當然,行是行的,這固然很好,可是千萬別鬧出什么亂子來啊。(《套中人》)

          17.面包!面包!我們要面包!(《萌芽》)

          18.我從沒有愛過這世界,它對我也一樣。(《拜倫詩選》)

          19. 愛情應該給人一種自由感,而不是囚禁感。(《兒子與情人》)

          20.暴風雨將要在那一天,甚至把一些槲樹吹倒,一些教堂的高塔要倒塌,一些宮殿也將要動搖!(《海涅詩選》)

          21.自己的行為最惹人恥笑的人,卻永遠是最先去說別人壞話的人。(《偽君子》)

          22.這時一種精神上的感慨油然而生,認為人生是由啜泣、抽噎和微笑組成的,而抽噎占了其中絕大部分。(《歐-亨利短篇小說選》)

          23.歷史喜愛英勇豪邁的事跡,同時也譴責這種事跡所造成的后果。(《神秘島》)

          24.整個下半天,人都聽憑羊脂球去思索。不過本來一直稱呼她作“夫人”,現在卻簡單地稱呼她作“小姐”了,誰也不很知道這是為著什么,仿佛她從前在 評價當中爬到了某種地位,現在呢,人都想把她從那種地位拉下一級似的,使她明白自己的地位是尚叩摹?(《莫泊桑短篇小說選》)

          25.如果冬天來了,春天還會遠嗎? (《雪萊詩選》)

          26.我明白了,我已經找到了存在的答案,我惡心的答案,我整個生命的答案。其實,我所理解的一切事物都可以歸結為荒誕這個根本的東西。(《惡心》)

          27.世界上有這樣一些幸福的人,他們把自己的痛苦化作他人的幸福,他們揮淚埋葬了自己在塵世間的希望,它卻變成了種子,長出鮮花和香膏,為孤苦伶仃的苦命人醫治創傷。(《湯姆叔叔的小屋》)

          28.當格里高?薩姆莎從煩躁不安的夢中醒來時,發現他在床上變成了一個巨大的跳蚤。(《變形記》)

          29.當現實折過來嚴絲合縫地貼在我們長期的夢想上時,它蓋住了夢想,與它混為一體,如同兩個同樣的圖形重疊起來合而為一一樣。(《追憶似水年華》)

          30.人與人之間,最可痛心的事莫過于在你認為理應獲得善意和友誼的地方,卻遭受了煩擾和損害。(《巨人傳》)

          31.現在我說的您要特別注意聽:在別人心中存在的人,就是這個人的靈魂。這才是您本身,才是您的意識在一生當中賴以呼吸、營養以至陶醉的東西,這也就是您的靈魂、您的不朽和存在于別人身上的您的生命。(《日瓦戈醫生》)

          32.美德猶如名香,經燃燒或壓榨而其香愈烈,蓋幸運最能顯露惡德而厄運最能顯露美德。(《培根論說文集》)

          33.親愛的艾妮斯,我出國,為了愛你,我留在國外,為了愛你,我回國,也是為了愛你!(《大衛-科波菲爾》)

          34.強迫經常使熱戀的人更加鐵心,而從來不能叫他們回心轉意。(《陰謀與愛情》)

          35.在各種事物的常理中,愛情是無法改變和阻擋的,因為就本性而言,愛只會自行消亡,任何計謀都難以使它逆轉。(《十日談》)

          36.只要你是天鵝蛋,就是生在養雞場里也沒有什么關系。(《安徒生童話》)

          37.就投機鉆營來說,世故的價值永遠是無可比擬的。(《死魂靈》)

          38.誰都可能出個錯兒,你在一件事情上越琢磨得多就越容易出錯。(《好兵帥克歷險記》)

          39.我們經歷著生活中突然降臨的一切,毫無防備,就像演員進入初排。如果生活中的第一次彩排便是生活本身,那生活有什么價值呢?(《生命中不能承受之輕》)

          40.他發現了人類行為的一********自己還不知道——那就是,為了要使一個大人或小孩極想干某樣事情,只需要設法把那件事情弄得不易到手就行了。(《湯姆-索亞歷險記》)

          41.對有信仰的人,死是永生之門。(《失樂園》)

          42.有一個傳說,說的是有那么一只鳥兒,它一生只唱一次,那歌聲比世上所有一切生靈的歌聲都更加優美動聽。(《荊棘鳥》)

          43.離開一輩子后,他又回到了自己出生的那片土地上。從小到大,他一直是那個地方的目擊者。(《尤利西斯》)

          44.同上帝保持聯系是一碼事,他們都贊同這一點,但讓上帝一天二十四小時都待在身邊就是另一碼事了。(《第二十二條軍規》)

          45.在甜蜜的夢鄉里,人人都是平等的,但是當太陽升起,生存的斗爭重新開始時,人與人之間又是多么的不平等。(《總統先生》)

          46.開發人類智力的礦藏是少不了要由患難來促成的。(《基度山伯爵》)

          47.離你越近的地方,路途越遠;最簡單的音調,需要最艱苦的練習。(《泰戈爾詩選》)

          48.悲傷使人格外敏銳。(《約翰-克里斯朵夫》 )

          49.我在女人跟前經常失敗,就是由于我太愛她們了。(《懺悔錄》)

          50.她睜大一雙絕望的眼睛,觀看她生活的寂寞。她像沉了船的水手一樣,在霧蒙蒙的天邊,遙遙尋找白帆的蹤影。(《包法利夫人》)


          posted @ 2007-09-09 15:04 dennis 閱讀(477) | 評論 (1)編輯 收藏

              jdk5引入的concurrent包來自于Doug Lea的卓越貢獻。最近我在查找服務器OOM的原因之后,決定采用這個包重寫應用中一個servlet,這個servlet調用了一個阻塞方法,當被阻塞之后,服務器中的線程數(因為阻塞了,后續請求不斷地新增線程)突然增加導致了服務器當機,因此決定采用一個線程池,并且設置超時,如果阻塞方法超過一定時間就取消線程。因為我們的項目仍然跑在jdk 1.4.2上面,短期內不可能升級到jdk5,還是要利用這個并發包。去這里下載源碼并自己打包成jar,加入項目的lib,然后利用PooledExecutorTimedCallable來實現我們的需求。首先是線程池,相當簡單:
          import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
          import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
          /**
           * <p>類說明:線程池</p>
           * <p>注意事項:</p>
           * <pre></pre>
           * <p>創建日期:Sep 7, 2007 1:25:33 PM</p>
          @author:dennis zane
           * 
          @version $Id:$
           
          */
          public class MyThreadPool{
              
          private static PooledExecutor exec = new PooledExecutor(new BoundedBuffer(
                      
          20), 30);
              
          static {
                  exec.setKeepAliveTime(
          1000 * 60 * 5);
                  exec.createThreads(
          5);
                  exec.setMinimumPoolSize(
          4);
              }

              
          public static void execute(final Runnable r)  throws InterruptedException{
              
              exec.execute(r);
             
          }

              
          public static void shutdown() {
                  exec.shutdownAfterProcessingCurrentlyQueuedTasks();
                  exec 
          = null;
              }

          }


              靜態初始化并設置一個PoolExecutor,設置空閑線程的存活時間為5分鐘,設置最小線程數為4,最大線程數為30,一開始創建5個線程以待使用(根據各自的應用調整這些參數),另外提供了shutdown方法以供ServeltContextListener的contextDestroyed方法調用以關閉線程池。那么,結合TimedCallable來實現提交線程的超時機制,調用類似:
                     //設置超時時間
                     private static final long timeout = 1000;
                     ......
                     ......
                 try{
                     Callable callable = new Callable() {
                          
          public Object call() {
                             
          return new YourProgram().run();                   
                          }
                      };
                      TimedCallable timedCallable 
          = new TimedCallable(callable, timeout);
                      FutureResult future 
          = new FutureResult();
                      Runnable cmd 
          = future.setter(timedCallable);
                      
          //提交給線程池來執行
                      MyThreadPool.execute(cmd);
                      //獲取任務結果
                      YourObject obj
          = (YourObject) future.get();
                      ......
                      ......
                   }
          catch (InterruptedException e) {
                      if (e instanceof TimeoutException) {
                           log.error("任務超時");
                            ...
                       }
                   }catch(InvocationTargetException e)
                   {
                      //清理任務..
                   }
                   ......
          如果不是很理解這段代碼,那么也許你應該先看看jdk5引入的Future、FutureTask等類,或者看看這里的文檔。對于超時時間的大小估算,你應當在生產環境中計算該阻塞方法的調用時間,正常運行一段時間,利用腳本語言(比如ruby、python)分析日志以得到一個調用花費時間的最大值作為timeout,這里的單位是毫秒。而線程池大小的估算,要看你提交給線程執行的任務的類型:如果是計算密集型的任務,那么線程池的大小一般是(cpu個數+1);如果是IO密集型的任務(一般的web應用皆是此類),那么估算有一個公式,
          假設N-cpu是cpu個數,U是目標CPU使用率,W/C是任務的等待時間與計算時間的比率,那么最優的池大小等于:
          N-threads=N-cpu*U*(1+W/C)
             

          posted @ 2007-09-09 14:23 dennis 閱讀(3874) | 評論 (0)編輯 收藏

          僅列出標題
          共56頁: First 上一頁 33 34 35 36 37 38 39 40 41 下一頁 Last 
          主站蜘蛛池模板: 巫溪县| 临洮县| 通城县| 桐庐县| 鄂州市| 大名县| 南溪县| 栾城县| 衡阳市| 陈巴尔虎旗| 朝阳区| 信阳市| 弥勒县| 隆德县| 东乡族自治县| 商河县| 蓬莱市| 岳西县| 老河口市| 那坡县| 思茅市| 白银市| 尼玛县| 潢川县| 馆陶县| 昌江| 沙坪坝区| 霞浦县| 墨玉县| 贵港市| 东乌珠穆沁旗| 庄河市| 万盛区| 黔西| 靖安县| 乌兰县| 时尚| 清流县| 沾化县| 思茅市| 华坪县|