庄周梦蝶

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

    jruby本质上也是启动一个jvm,然后去读Ruby脚本并解释执行(也可以编译),因此jprofiler理所当然也可以去监控jruby脚本的执行。
执行     
jruby hello.rb
等价于执行:
java -Xmx378m -Xss1024k  -Djruby.home=/usr/local/jruby
                                   -
Djruby.lib=/usr/local/jruby/lib Djruby.script=jruby org.jruby.Main hello.rb
这一点,你可以通过ps aux |grep jruby 看到。因此配置jprofiler就简单了,在VM arguments加上这些参数(可以包括jruby的参数),比如我的VM arguments配置如下:

-server -Xmx378m -Xss1024k -Djruby.script=jruby -Djruby.thread.pooling=true
                  
-Djruby.jit.threshold=-Djruby.compile.fastest=true
                   -
Djruby.home=D:\jruby\jruby-1.1RC2 -Djruby.lib=D:\jruby\jruby-1.1RC2\lib

Main class or executable JAR填上:org.jruby.Main。然后就是Arguments一栏填上你的脚本位置:
D:\ruby\lib\hello.rb

最后,别忘了将jruby/lib目录下的bsf.jar和jruby.jar加入Class Path。

大功告成,你可以用jprofiler去观察GC、线程和锁、Heap等等了。

posted @ 2008-03-24 15:26 dennis 阅读(1491) | 评论 (0)编辑 收藏

    看了javaeye上一个解决约瑟夫环的问题的帖子,就想能不能用scheme来解决。如果采用推导出的数学公式来处理当然很简单了:
(define (joseph n m)
  (define (joseph
-iter init s)
    (
if (> init n)
        (
+ s 1)
        (joseph
-iter (+ init 1) (remainder (+ s m) init))))
  (joseph
-iter 2 0))
    我想是否可以用一般的模拟算法来实现?也就是模拟一个循环链表,每次删除第m个元素。弄了个比较丑陋的实现:

(define (enumrate-interval low high)
  (
if (> low high)
      
'()
      (cons low (enumrate-interval (+ low 1) high))))
(define (delete
-last list)
  (
if (eq? (cdr list) '())
      '()
      (cons (car list) (delete-last (cdr list)))))

(define (joseph
-iter init list it) 
  (let ((m (remainder it (length list))))
   (cond ((
= m 0) (delete-last list))
         ((
= m 1) (append (cdr list) (reverse init)))
         (
else
           (joseph
-iter (cons (car list) init) (cdr list) (- m 1))))))
(define (joseph n m)
    (define (joseph
-list list m)
      (display list) 
      (newline)
      (
if (eq? (cdr list) '())
          (car list)
          (joseph
-list (joseph-iter '() list m) m)))

计算(joseph 8 3)的过程如下:
(1 2 3 4 5 6 7 8)
(4 5 6 7 8 1 2)
(7 8 1 2 4 5)
(2 4 5 7 8)
(7 8 2 4)
(4 7 8)
(4 7)
(7)
7

看了这个计算过程就知道我这个方法多糟糕,每次都重新构造列表。不知道看blog的大大们有没有更好的思路?

posted @ 2008-03-20 19:15 dennis 阅读(738) | 评论 (2)编辑 收藏

1、应当有一个详查表,关注reviewer过去遇到的问题和缺陷,对常见错误保持警惕

2、详查应当专注于检测错误,而非修正

3、详查的角色包括:
1)主持人:负责分配复查任务,报告详查结果,主持详查回忆,他需要能够理解被详查代码的相关技术细节,整体上控制详查进度
2)作者:代码的作者,负责陈述项目的概况,解释设计和代码中不清晰的部分
3)复查者(reviewer,《代码大全2》称为评论员,感觉不是很恰当):负责实际复查的工作的执行,负责找出缺陷。
4)记录员:记录发现的错误,记录任务的指派情况,记录会议
5)管理人员:详查是一个纯技术性的复查,应当避免管理人员的介入。如果管理人员介入了详查,那么参与的人可能会觉的在被评价,而不是去复查材料,导致焦点从技术问题转移到行政问题。按国情,这种情况相当常见。

4、明确详查的目的是发现设计或者代码的缺陷,而不是探索替代方案,或者争论谁对谁错,其目的绝不应该是批评作者的设计和代码。如果出现复查者做出不恰当的评价和发言,主持人应该制止,引导详查的活动的健康进行。这一点我觉的相当重要,对事而不对人。

5、详查会议后,主持人撰写详查报告,最好能提交给管理人员一份,并且应当及时进入返工环节,将缺陷分配给某人去修复(往往是原作者),并及时跟进监督缺陷的修复情况。


posted @ 2008-03-20 10:27 dennis 阅读(1474) | 评论 (1)编辑 收藏

    读《代码大全2》,已经读了一半,喘口气。总结八个字:百科全书,受益匪浅。小到一个赋值语句、一个循环的编写,大到需求分析、架构设计,无所不包,看后半部分目录,更是扯到了重构、软件工艺、程序员的性格特征这样的话题。恰好手边的工作暂时比较有闲,可以实践下“创建高质量的代码”中的部分建议,晚上读书,第二天就重构,乐在其中。这一部分中对设计、子程序、类、变量、语句的处理建议,可能你平常已经在这么做,可作者这么精辟地概括出来让人叹服,而有些地方是你平常绝对很少注意的,特别是在变量和三种常见控制语句的处理上。
  
    说说我认为是缺点的地方,就是作者貌似对函数式语言了解很少,举的例子全部用的是广泛应用的静态语言(c/c++,java,vb)。例如作者有这么一句话:如果为我工作的程序员用递归去计算阶乘,那么我宁愿换人。作者对递归的态度相当谨慎,这在静态命令式语言中显然是正确的,但是在函数式语言中,由于有尾递归优化的存在,递归反而是最自然的形式,况且我打心里认为递归更符合人类思维。请注意,在FP中只有尾递归的程序才是线性迭代的,否则写出来的递归可能是线性递归或者树形递归,两种情况下都可能导致堆栈溢出并且性能较差。

scheme写阶乘:
(define (fac n)
  (
if (= 1 n)
      
1
      (
* n (fac (- n 1)))))
显然这个版本不是尾递归,计算过程是一个线性递归过程,计算(fac 4)的过程如下:
(* 4 (fac 3))
(* 4  (3 * (fac 2)))
(* 4  (3 * (* 2 (fac 1))))
(* 4  (3 * (* 2 1)))
(* 4  (3 * 2))
(* 4 6)
24
    因为解释器是采用应用序求值,需要将表达式完全展开,然后依次求值,在这个过程中,解释器内部需要保存一条长长的推迟计算的轨迹。
改写成一个尾递归版本:
(define (fac n)
  (define (fac
-iter product n)
    (
if (= 1 n)
        product
        (fac
-iter (* n product) (- n 1))))
  (fac
-iter 1 n))
我们来看看它的计算过程:
(fac-iter 1 4)
(fac-iter 4 3)
(fac-iter 12 2)
(fac-iter 24 1)
24
可以看到,在这个过程中,解释器不需要保存计算轨迹,迭代的中间结果通过product变量来保存,这是一个线性迭代的计算过程。
最后再看一个斐波拉契数列的例子:
(define (fib n)
  (cond ((
= n 0) 0)
            ((
= n 11)
            (
else
                 (+ (fib (- n 1))  (fib (- n 2))))))

这个计算过程展开是一个树形递归的过程(为什么说是树形?展开下计算过程就知道),改写为线性迭代:
(define (fib n)
  (define (fib
-iter a b count)
     (
if (= count 0)
         b
         (fib
-iter (+ a b) a (- count 1))))
 (fib
-iter 1 0 n))

     上述的内容在sicp第一章里有更详细的介绍和讨论。

posted @ 2008-03-18 19:34 dennis 阅读(7684) | 评论 (11)编辑 收藏

    swf-util是一个使用Ruby读取swf头信息(高度、宽度、文件大小、帧数等等)、压缩和解压缩swf文件的工具类库,改写自java版本
项目主页:http://code.google.com/p/swf-util/
协议:MIT License
平台:JRuby or c ruby 1.8.x on linux
依赖BitStruct,请到这里下载安装bit-struct。在windows上的Ruby Zlib的实现有问题,linux下正常,使用JRuby也可以。
使用例子:
#read swf head
require 'swf_util'

header=SwfUtil::read_header("test.swf")
puts header.inspect
header.version
header.frame_rate
header.width
header.frame_count


#decompress swf
SwfUtil::decompress_swf("test.swf")

#compress swf
SwfUtil::compress_swf("test.swf")


posted @ 2008-03-11 14:41 dennis 阅读(1119) | 评论 (0)编辑 收藏

   

     1908年的3月9日,四十多名“叛逃者”在奥雷菲奇的洛奥洛吉奥饭馆聚会, 宣布成立国际米兰足球俱乐部,吉奥瓦尼.帕拉米西奥蒂成为俱乐部第一任主席,俱乐部成立宣言如下:”nascerà qui, al ristorante “l'orologio”, ritrovo di artisti e sarà sempre una squadra di talento. Questa notte splendida darà i colori al nostro stemma: il nero e l'azzurro sullo sfondo d'oro delle stelle. Si chiamerà Internazionale, perchè noi siamo fratelli del mondo." ( 她在时钟餐馆出生,重新找到艺术而且将永远是一支富有才华的球队。这个精彩的夜晚给了我们徽章的颜色:蓝色和黑色在金黄色的星状背景上面。她叫国际,因为 我们是世界的兄弟!)意大利《米兰日报》的国际米兰专家蒙蒂说:“他们选择的新球衣的颜色反映了他们浪漫主义倾向,黑色代表黑夜,而蓝色代表大海。”

    inter 100岁了,而我成为它的球迷也已经有10年了,怒过、骂过、笑过甚至哭过,多少个熬夜看球的夜晚,点点滴滴涌上心头。

posted @ 2008-03-10 18:38 dennis 阅读(469) | 评论 (1)编辑 收藏

    最近一直在写Ruby脚本,说出来你可能不相信,我用Ruby写游戏脚本。用的是JRuby,采用JRuby是因为定时器的问题,Ruby1.8.6因为线程是用户空间内的本地线程,标准库没有提供强大的定时器功能,而对于游戏逻辑有相当多的任务需要定时处理,权衡之下,最后决定使用JRuby,封装了java的ScheduledExecutorService,等以后Ruby有更完善的定时器的时候就切换回来(我猜测引入了native thread的Ruby1.9应该有更强大的定时器),基本满足了要求。这一过程也更让我觉的JRuby是个非常有前途的项目,利用Ruby的语法以及动态语言的高效加上java极其丰富的类库,这样的组合有莫大的威力,况且 JRuby的性能比之c ruby在某些方面更有优势,在1.1出来后应该可以有一个更大的提升。

    写Ruby脚本唯一比较郁闷的是重构,尽管Netbeans比RDT提供了更好的重构功能,但是对于一些复杂重构仍然没有比较好的支持,况且我也不敢完全信任IDE的自动化,这种时候更显示出完备的单元测试的重要性,如果没有单元测试,对Ruby脚本的重构简直难以想象。另外一个比较麻烦的是,Ruby对二进制的处理并不是很方便,尽管使用了bit-struct,但是它只能支持定长的数据结构,而不是可变长度的array list,变长的string,或者switch结构;尽管我自己做了简单的扩展,仍然很局限。幸好我遇到这样的情况不多,通过其他手段变通处理也还能接受。后来javaeye上的庄表伟老大发布了DynamicStruct,这个才是根本解决之道,两者结合使用应该可以处理所有情况了。不过那时我的协议处理部分都已经完成,下次有机会再试试。
    读书嘛,最近终于开始读买了许久的《代码大全2》,以前是真怕这种大部头,看着就没信心读完,哇哈哈,没想到一读下去就一发不可收拾,真是好书一本,就软件构建中的设计一章就值回书钱了。又利用晚上在重读sicp前三章,在注释这样的边边角角原来也非常有价值,例如对闭包和组合的解释,静态语言由于有太多的声明式结构(struct、class etc.)反而对组合造成了阻碍和惩罚,而在Lisp中由于通用的组合粘合剂cons的存在,可以以一种统一的方式去处理组合结构,模拟各种复杂的数据结构。今天托同事在当当上买的书到了,《unix编程艺术》到手,这书按牛人的说法是sicp的实践版,不读就相当遗憾了。

posted @ 2008-03-04 19:09 dennis 阅读(666) | 评论 (1)编辑 收藏

重定向标准输入的实现:
1)close-then-open: close(0) ; fd=open("test",O_RDONLY); fd将是stdin。
2)open-close-dup-close:
fd=open(file),打开stdin将要重定向的文件;close(0);new_fd=dup(file);close(fd);new_fd就是被重定向的stdin
3)open-dup2-close:
fd=open(file);new_fd=dup2(fd,0);close(fd);

重定向标准输出的实现:
  父进程fork();子进程close(1);create("g",0644),此时子进程的stdout被重定向到g;接下来子进程exec某个程序,文件描述符属于进程属性,exec调用不会改变他们,那么运行的程序的标准输出将被送到g,由此实现了标准输出重定向。

本质上重定向的实现是依赖两个原则:
1、标准输入、标准输出和标准错误分别是0、1和2
2、最低可用描述符:打开文件时,为此文件安排的描述符总是进程内打开文件数组的最低可用位置的索引。

管道:
  匿名管道:适合于有亲缘关系的进程,通过pipe函数实现。
  有名管道:通过mkfifo函数实现,实现进程间的双向通讯可以采用两个有名管道实现,也可以采用socketpair调用。

posted @ 2008-02-29 11:16 dennis 阅读(918) | 评论 (0)编辑 收藏

    今天有点空闲,想想用Ruby写个NFA试试。从正则表达式构造NFA采用经典的Thompson算法:正则表达式 -> 后缀表达式 -> 构造NFA。构造了NFA后,用之匹配字符串。一句话,写了个玩具的正则表达式引擎,支持concatenation、alternation以及*、?、+量词,不支持反向引用和转义符。测试了下与Ruby自带的正则表达式引擎的性能对比,慢了3倍。构造NFA没什么问题,主要是匹配运行写的烂,有空再改改。

nfa.rb

module NFA
  
class NFA
    
def initialize(state)
      @state
=state
    end
    
def step(clist,c)
      
return clist if clist.size==0;
      nlist
=[] 
      allNull 
= true
      matched 
= false
      clist.each do 
|t|
        
if !t.nil?
          allNull 
= false if t.c!=-1
          
if t.c == c && t.end.type ==1 then
            matched 
= true
            nlist.push(t.end.out1) 
if !t.end.out1.end.nil? 
            nlist.push(t.end.out2) 
if !t.end.out2.end.nil?
          elsif (t.c 
== c && t.end.type == 0) then
            matched 
= true;
            
return ListUitls.new_list(t);
          elsif (t.c 
== -1 && !t.end.nil?) then
            nlist.push(t.end.out1);
            nlist.push(t.end.out2);
          end
        end
      end        
      
return step(nlist, c) if (allNull)
      
return step(nlist, c) if (!matched)
      nlist
    end
    
def test?(s)
      match(@state,s)
    end
    
def match(state,s)
      clist 
=[]
      clist.push(state.out1);
      clist.push(state.out2);
      s.each_byte do 
|c|
        c 
=c&0xFF;
        clist 
= step(clist, c);
        
return false if clist.size==0
      end
      
return is_match?(clist)
    end
    
def is_match?(clist)
      clist.each  do 
|t|
        
return true if !t.nil? and t.c==-1 and t.end and t.end.is_matched? 
      end
      false
    end
  end
  
class Paren
    attr_accessor:n_alt,:n_atom
  end
  
class State
    attr_accessor :out1,:out2,:type
    
def initialize(out1,out2)
      @out1
=out1
      @out2
=out2
      @type
=1
    end
    
def is_matched?
      
return @type==0
    end
  end
  
class Transition
    attr_accessor :c,:end
    
def initialize(c)
      @c
=c
    end   
  end
  
class Frame
    attr_accessor :start,:outs
    
def initialize(start,outs)
      @start
=start
      @outs
=outs
    end
  end
  
class ListUitls
    
def self.link(list,state)
      list.each{
|t| t.end=state}
    end
    
def self.append(list1,list2)
      list1
+list2
    end
    
def self.new_list(out)
      result
=[]
      result.push(out)
      result      
    end
  end
  
def self.compile(re)
    post 
= re2post(re)
    
raise ArgumentError.new,"bad regexp!" if post.nil?
    state 
= post2nfa(post);
    
raise RuntimeError.new,"construct nfa from postfix fail!" if state.nil?        
    
return NFA.new(state);
  end
  
def self.post2nfa(postfix)
    stack
=[]
    s
=nil
    t
=t1=t2=nil 
    e1
=e2=e=nil 
    
return nil if postfix.nil?
    postfix.each_byte do 
|p|
      case p.chr
      when 
'.':
        e2 
= stack.pop() 
        e1 
= stack.pop() 
        ListUitls.link(e1.outs, e2.start) 
        stack.push(Frame.new(e1.start, e2.outs)) 
      when 
'|':
        e2 
= stack.pop() 
        e1 
= stack.pop() 
        t1 
= Transition.new(-1)
        t2 
= Transition.new(-1
        t1.end 
= e1.start 
        t2.end 
= e2.start 
        s 
= State.new(t1, t2) 
        stack.push(Frame.new(s, ListUitls.append(e1.outs, e2.outs))) 
      when 
'?':
        e 
= stack.pop() 
        t1 
= Transition.new(-1)
        t2 
= Transition.new(-1
        t1.end 
= e.start 
        s 
= State.new(t1, t2) 
        stack.push(Frame.new(s, ListUitls.append(e.outs, ListUitls.new_list(t2)))) 
      when 
'*':
        e 
= stack.pop() 
        t1 
= Transition.new(-1)
        t2 
= Transition.new(-1)
        t1.end 
= e.start 
        s 
= State.new(t1, t2) 
        ListUitls.link(e.outs, s) 
        stack.push(Frame.new(s, ListUitls.new_list(s.out2))) 
      when 
'+':
        e 
= stack.pop() 
        t1 
= Transition.new(-1
        t2 
= Transition.new(-1)
        t1.end 
= e.start 
        s 
= State.new(t1, t2) 
        ListUitls.link(e.outs, s) 
        stack.push(Frame.new(e.start, ListUitls.new_list(t2))) 
      
else
        t 
= Transition.new(p) 
        s 
= State.new(t, Transition.new(-1)) 
        stack.push(Frame.new(s, ListUitls.new_list(s.out1))) 
      end
    end
    e 
= stack.pop() 
    
return nil if stack.size()>0
    end_state 
= State.new(nil, nil) 
    end_state.type
=0
    e.outs.each do 
|tran|
      
if tran.c!=-1
        t1 
= Transition.new(-1)
        t2 
= Transition.new(-1
        s
=State.new(t1,t2)
        tran.end
=s
        s.out1.end
=end_state
        s.out2.end
=end_state
      
else
        tran.end
=end_state         
      end
    end
    start 
= e.start 
    
return start 
  end
  
def self.re2post(re)
    n_alt 
= n_atom = 0 
    result
=""
    paren
=[]
    re.each_byte do 
|c|
      case c.chr  
      when 
'(' then
        
if (n_atom > 1) then
          n_atom
-=1 
          result
<<"."
        end
        p 
=Paren.new 
        p.n_alt 
= n_alt 
        p.n_atom 
= n_atom 
        paren.push(p) 
        n_alt 
= n_atom = 0
      when 
'|' then
        
if (n_atom == 0)
          
return nil
        end
        
while (n_atom-=1> 0 
          result
<<"."
        end
        n_alt
+=1
      when 
')' then
        
if (paren.size() == 0)
          
return nil
        end                
        
if (n_atom == 0)
          
return nil 
        end
        
while (n_atom-=1)>
          result
<<"." 
        end
        
while(n_alt>0)  
          result
<<"|" 
          n_alt
-=1
        end
        p 
= paren.pop()
        n_alt 
= p.n_alt 
        n_atom 
= p.n_atom 
        n_atom
+=1
      when 
'*','+','?':
        
if (n_atom == 0)
          
return nil 
        end
        result
<<
      
else 
        
if (n_atom > 1
          n_atom
-=1 
          result
<<"."
        end
        result
<<
        n_atom
+=1
      end
    end
    
return nil if paren.size()>0
    
while ( (n_atom-=1)> 0)
      result
<<"." 
    end
    
while(n_alt>0)
      n_alt
-=1
      result
<<"|" 
    end
    result
  end
end

使用:
 nfa = NFA::compile("a(bb)+a(cdf)*")
 
assert nfa.test?("abba")
 
assert nfa.test?("abbbba")
 
assert !nfa.test?("a"
 
assert !nfa.test?("aa"
 
assert nfa.test?("abbacdf")
 
assert nfa.test?("abbbbacdfcdf")
 
assert !nfa.test?("bbbbacdfcdf")
 
assert !nfa.test?("abbbacdfcdf")
 
assert !nfa.test?("abbbbacdfdf")
 
assert !nfa.test?("abbbbacdfdfg")


posted @ 2008-02-25 17:46 dennis 阅读(1327) | 评论 (1)编辑 收藏

    在《程序员》最新一期有个专题介绍java开源nio框架,其中谈到了mina和grizzly。mina我还算比较熟悉,写过一些代码,也尝试去读过源码。而grizzly是第一次听说,这个项目是sun的一个开源nio框架,是2004年在GlassFish项目中诞生的,一开始是一个http web server,用于取代Tomcat的Coyote Connector和Sun WebServer,2007年7月1.5版本发布并宣布成为开源项目,项目主页在https://grizzly.dev.java.net
    grizzly与mina的性能比较(基于2007年JavaOne会议上的ppt)


    GlassFish vs Tomcat


  
     grizzly的设计与一般的nio框架相比是比较不同的,主要不同点在于读和写都是采用blocking方式,并且使用临时selector;线程模型可配置,不过据作者介绍在跑一个selector主线程处理ACCEPT,用线程池处理read和write性能表现最好,这点不出意料。

posted @ 2008-02-23 19:13 dennis 阅读(5082) | 评论 (2)编辑 收藏

仅列出标题
共56页: First 上一页 28 29 30 31 32 33 34 35 36 下一页 Last