庄周梦蝶

生活、程序、未来
   :: 首页 ::  ::  :: 聚合  :: 管理

   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 阅读(2180) | 评论 (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 阅读(7929) | 评论 (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 阅读(654) | 评论 (0)编辑 收藏

    今天向公司提出辞职了,考虑这么久,还是决定辞职。我不想浪费大半年时间做维护,大部分时间无所事事,这是我不能接受的。我需要更多的项目经历来锻炼自己。在公司这一年,学到的不少,无论从做人还是技术上都有所感悟,接下来确定去厦门,未来将怎么样?还是充满希望和憧憬,希望好运吧。

posted @ 2007-09-20 12:48 dennis 阅读(565) | 评论 (4)编辑 收藏

     摘要:     update1:添加了remove,removeAll()方法以及getSize()方法     update2:添加了keySet()方法用于迭代       update3:经过测试,StTable类在存储Integer类型key时,put的速度比HashMap快了接近3倍,而...  阅读全文

posted @ 2007-09-18 19:28 dennis 阅读(1347) | 评论 (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 阅读(1129) | 评论 (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 阅读(8120) | 评论 (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 阅读(1925) | 评论 (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 阅读(466) | 评论 (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 阅读(3869) | 评论 (0)编辑 收藏

仅列出标题
共56页: First 上一页 33 34 35 36 37 38 39 40 41 下一页 Last