庄周梦蝶

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

    有段时间没更新blog了。主要是这段时间内自己处于一个比较莫名的阶段,静不下心来做事读书,或者说不知道自己应该做什么。原因有工作上的调动问题,有生活中的一些压力。最近了换了项目小组,与arbow一起去搞某个产品的分布方案。这个产品已经比较稳定,我过去没有参与过它的开发工作,没有经历过这个开始显的有点复杂的项目从无到有的过程,因此对代码、对业务、对组员都显的比较陌生。
    过往的项目经历都是在别人给出明确目标下的开发工作,或者说习惯于接受别人安排的任务,有的放矢地去实现一些东西。而现在的处境是到一个不熟悉的项目,去实现一个不大明确的目标,因而我自己有点搞不清楚状况,再加上生活中那么些压力,心态也出了问题,很被动地去等待,而非积极地去探讨和介入这些工作,简单点说,有点像局外人的感觉。
    今天跟经理谈了下,我觉的自己最近的效率和状态很差,想请假休息。经理跟我聊了些他的经验,我才明白自己的问题所在。过于急躁和被动,这不是休息能解决,首要的还是要调整心态,以踏实谦虚的心理去学习新东西,主动去做些事情,这样才能找回那份工作热情。
    题外话,广州真的好热,我这个福建人都很不习惯。热还罢了,最主要是比较潮湿和闷气,这两天终于下雨了,感觉清爽很多。

posted @ 2008-08-06 23:02 dennis 阅读(406) | 评论 (0)编辑 收藏

    Ruby也能写servlet?是的,没开玩笑,而且挺方便的,因为Ruby的标准库就自带了一个webrick,webrick本身又有一个serlvet容器,随时随地启动一个web server,实在是很方便。
    先看个最简单的例子,输出hello到浏览器:
require 'webrick'
require 
'net/http'
include WEBrick

class HelloServlet < HTTPServlet::AbstractServlet
  
def hello(resp)
    resp[
"Content-Type"]="text/html;charset=utf-8"
    resp.body
="hello,ruby servlet"
  end
  private :hello
  
def do_GET(req,resp)
    hello(resp)
  end
  
def do_POST(req,resp)
    hello(resp)
  end
end
if $0==__FILE__
  server
=HTTPServer.new(:Port=>3000)
  server.mount(
"/hello",HelloServlet)
  trap(
"INT"){ server.shutdown }
  server.start
end
    是不是跟java很像?所有的serlvet都要继承自HTTPServlet::AbstractServlet,并实现do_GET或者do_POST方法。在这行代码:
server=HTTPServer.new(:Port=>3000)

    我们启动了一个HTTP Server,端口是3000,然后将HelloServlet挂载到/hello这个路径上,因此,执行这个脚本后,可以通过http://localhost:3000/hello调用HelloServlet,简单地只是显示字符串"hello,ruby servlet"。
   
这个简单的例子没有任何交互,并且显示的html也是写死在脚本中,显然更好的方式应该通过模板来提供,可以使用Ruby标准库的erb模板。再给个有简单交互的例子,现在要求用户输入姓名,然后提交给HelloServlet,显示"hello,某某某"。嗯,来个最简单的提交页面:
<html>
<body>
<center>
   
<form action="http://localhost:3000/hello" method="post">
     
<input type="text" name="name" size=10/><br/><br/>
     
<input type="submit" name="submit" value="submit"/>
   
</form>
   
</center>
</body>
</html>

    注意到,我们采用POST方法提交。再看看erb模板:
<html>
    
<head></head>
    
<body>
      hello,
<%=name%>
    
</body>
</html>   
    其中的name是我们将要绑定的变量,根据用户提交的参数。最后,修改下HelloServlet:
require 'webrick'
require 
'net/http'
include WEBrick

class HelloServlet < HTTPServlet::AbstractServlet
  
def do_GET(req,resp)
    do_POST(req,resp)
  end
  
def do_POST(req,resp)
    name
=req.query["name"]
    
#读取模板文件
    template=IO.read(File.dirname(__FILE__)+"/hello.html")
    message
=ERB.new(template)
    resp[
"Content-Type"]="text/html;charset=utf-8"
    resp.body
=message.result(binding)
  end
end
if $0==__FILE__
  server
=HTTPServer.new(:Port=>3000)
  server.mount(
"/hello",HelloServlet)
  trap(
"INT"){ server.shutdown }
  server.start
end
    与前一个例子相比,不同点有二,一是通过req.query["name"]获得用户提交的参数name,二是resp的body是由模板产生,而不是写死在代码中。在一些临时报表、临时数据的展示上,可以充分利用Ruby的这些标准库来快速实现。
   

posted @ 2008-07-23 12:02 dennis 阅读(2879) | 评论 (0)编辑 收藏

1、如果用java6的ScriptEngineManager来调用JRuby,并且脚本使用到了Ruby的标准库(比如我用到了YAML库),如果没有正确设置,是会找不到标准库的。通过打印$:变量可以看到文件的加载路径,比如在某台机器上的打印的结果:
   puts $:
   输出:
.
/root/.jruby/lib/ruby/site_ruby/1.8
/root/.jruby/lib/ruby/site_ruby
/root/.jruby/lib/ruby/1.8
/root/.jruby/lib/ruby/1.8/java
lib/ruby/1.8
......略

显然,默认会到当前用户的主目录下寻找.jruby隐藏目录,将此目录作为Ruby的安装目录,因此,可以在~user/.jruby放置一个jruby实现,一劳永逸地解决问题,不然就要自己手工添加完整的路径到$:变量中。

2、nio的临时selector的使用,了解grizzly的都知道,Grizzly框架有一个比较与众不同的地方在于使用临时selector注册channel进行读或者写。这个带来什么好处呢?一个是,通常我们可能将read派发到其他线程中去,如果一次没有读完,那么就得继续注册OP_READ到主selector上;注意,nio在一些平台上有个问题,就是SelectionKey.interestOps方法跟Selector.select方法会有并发冲突,产生奇怪的现象,因此,你会看到大多数的nio框架都会保证SelectionKey.interestOps跟Selector.select的调用在同一个线程;在没有读完继续注册这个场景下,免不了线程间的context switch,如果采用一个临时selector注册并读取,就可以避免这个切换开销。另外,对于write调用,通常你可能这样写:
while (byteBuffer.hasRemaining()) {
  
int len = socketChannel.write(byteBuffer);
  
if (len < 0){
   
throw new EOFException(); 
  }
}


   在负载比较高的时候,write返回0的次数会越来越多,while循环将空耗多次导致CPU占用偏高,这个问题在win32上比较严重,同样可以采用临时selector的解决(Cindy2.x是留在队列,等待下次写)。下例是采用临时Selector进行读的例子:

                Selector readSelector = SelectorFactory.getSelector();
                SelectionKey tmpKey 
= sc.register(readSelector,
                        SelectionKey.OP_READ);
                tmpKey.interestOps(tmpKey.interestOps() 
| SelectionKey.OP_READ);
                
int code = readSelector.select(1000);
                tmpKey.interestOps(tmpKey.interestOps()
                        
& (~SelectionKey.OP_READ));
                
if (code > 0) {
                    
do {
                        n 
= sc.read(in);
                    } 
while (n > 0 && in.hasRemaining());
                    in.flip();
                    decode();
                    in.compact();
                }
                SelectorFactory.returnSelector(readSelector);
    这样的方式,某种意义上可以认为是non-blocking模式下的阻塞读,在网络条件稳定的情况下(比如内网),能带来比较高的效率。

3、spymemcached,是另一个memcached的java client实现,采用nio。最近遇到的问题是它跟原来的MemcachedClient的兼容问题,用它去操作MemcachedClient存储的数据。spymemcached是通过Transcoder来实现序列化,Transcoder的WhalinTranscoder实现类兼容了Greg Whalin的MemcachedClient:
private Transcoder whalinTranscoder = new WhalinTranscoder();


Future
<Object> f = memcachedClient.asyncGet(id, whalinTranscoder);

   各个方法都有重载的版本用以指定Transcoder。

posted @ 2008-07-07 20:41 dennis 阅读(1255) | 评论 (2)编辑 收藏

    http://wuhanpin.blogcn.com/index.shtml,来自一线记者关于XXXX事件的blog,谎话重复千遍也就成了真理,但是历史终将还原真实。要看的赶紧看哦,过不了几天恐怕要被河蟹了。

posted @ 2008-07-03 09:16 dennis 阅读(555) | 评论 (0)编辑 收藏

    沸沸扬扬的华南虎案(更想说是闹剧)终于告一段落,在广大网民的火眼金睛下,假老虎终究没有变成真老虎,没有上演指“画”为“虎”的现代成语故事。尽管处理结果有那么点抓小放大的意思,但还是值的纪念的一个日子。
更正:我还是太乐观了,贵州某地发生的事情,让我无法平静,我能做些什么?

posted @ 2008-06-29 16:07 dennis 阅读(463) | 评论 (0)编辑 收藏

    主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒,因而,TIME_WAIT状态一般维持在1-4分钟。
    TIME_WAIT状态存在的理由:
1)可靠地实现TCP全双工连接的终止
    在进行关闭连接四路握手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须维护状态信息允许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,服务器将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的客户端必须维持状态信息进入TIME_WAIT状态。

2)允许老的重复分节在网络中消逝 
    TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时候,来自连接先前化身的重复分组已经在网络中消逝。

新的SCTP协议通过在消息头部添加验证标志避免了TIME_WAIT状态。

posted @ 2008-06-23 01:25 dennis 阅读(17829) | 评论 (3)编辑 收藏

    欧洲杯开赛至今,由于要上班,担心起不了床,完整的比赛没看过几场,错过好多场精彩对决了,今天晚上熬夜看俄罗斯VS.荷兰,真值了,阿尔沙文成了俺的新偶像,过人如草芥,太牛X了。这厮在FM2008里就很猛了,我的朴茨茅斯档第一个买的就是他,第一年就排上了联赛第三,让他打前腰,助攻第一,进球全队第三,性价比超值。


posted @ 2008-06-22 05:43 dennis 阅读(507) | 评论 (0)编辑 收藏

    加班在国内的公司好像是司空见惯的事情,更司空见惯的是加班不给加班费。从业三年,加班次数也不少,不过最长的一次是连续加了一个月的班,天天10点多才回家,比起某些同学深更半夜还在加班的差了些。在目前的公司,除了刚开始偶尔加班外,现在我基本就是下班就走人了,还没有因为我负责的模块延期导致的项目的延期,相反,自信工作的效率还是比较高的,自然上班时间能搞定的事情,何必拖到下班后?
    不排除有些人喜欢安静的环境,下班后,人少了,一个人敲代码感觉更好,效率更高。这其实颠倒了问题的本质,本质是公司没有为员工创造一个舒适的工作环境,“家具警察”们是绝不乐意给你安排一个私人小空间的。问题是,代码不是生活的全部,如果天天这样晚上在公司加班,可以想见这人的生活该如何枯燥,而生活枯燥的人很容易失去想象力和直觉,并且心理上难免会有点毛病。公司不应该鼓励加班,公司应该鼓励的是大家在上班期间高效地完成工作,然后尽快回家去“生活”。其实吧,如果我们上班少看点新闻,少开点小差,这个效率绝对是不低的。
    听闻有领导对我们部门不满,说我们部门总是下班后人都走光了:)这样的观点真是奇怪,难道加班就能显示这个部门很努力、很负责?况且,我看到很多加班的同学更多是在玩游戏或者干自己的事情,公司领导们难道看不到这一点?或者他们只要看见有人在那,心里就比较舒服点。这其实很奇怪的,我认为经常加班的部门绝对是有问题的,而且很大程度上是项目管理不当引起的。

posted @ 2008-06-21 12:32 dennis 阅读(1123) | 评论 (11)编辑 收藏

    SocketChannel和ServerSocketChannel,两者的父类是SelectableChannel,它在jdk中的文档有这么段话:

    Once registered with a selector, a channel remains registered until it is deregistered.This involves deallocating whatever resources were allocated to the channel by the selector.
    A channel cannot be deregistered directly; instead, the key representing its registration must be cancelled. Cancelling a key requests that the channel be deregistered during the selector's next selection operation.

    也就是说关闭一个已经注册的SelectableChannel需要两个步骤:

1)取消注册的key,这个可以通过SelectionKey.cancel方法,也可以通过SelectableChannel.close方法,或者中断阻塞在该channel上的IO操作的线程来做到。

2)后续的Selector.selectXXX方法的调用才真正地关闭本地Socket。

    因而,如果,如果在取消SelectionKey后没有调用到selector的select方法(因为Client一般在取消key后, 我们都会终止调用select的循环,当然,server关闭一个注册的channel我们是不会终止select循环的),那么本地socket将进入CLOSE-WAIT状态(等待本地Socket关闭)。简单的解决办法是在 SelectableChannel.close方法之后调用Selector.selectNow方法,类似:

   Selector sel;
   SocketChannel sch;
   // …
   sch.close();
   sel.selectNow();


    Nio编程有很多这样细节性的东西需要注意,通常情况下还是利用成熟的框架为妙。

posted @ 2008-06-18 01:50 dennis 阅读(2447) | 评论 (2)编辑 收藏

  JavaOne2008上有个session《Upcoming Java Programming Language Features》,讲了即将到来的jdk7可能引入的新的语言特性,比较开眼界的是jsr308对Annotation的扩展使用,更多地作为断言或者说checker使用以便减少bug。在ppt前面,我觉的更有意思的是对java语言演化的讲述,做个笔记。

1、应用VS.语言

应用是特性越多越好,应用是rich的;而语言是pure的,更少的、普通的特性更好。

2、添加一个java语言特性的三个前提:尊重过去、着眼未来以及顾及模型。

无论是增加、减少或者改变一个feature都可能broken已经存在的代码,一个新增加的feature必须兼容已经存在的代码,兼容是个沉重的包袱,就java语言而言,我相当认同尊重过去这一点,哪怕加入闭包这样的特性也不应当以损坏兼容性为代价,更好的选择是将这些特性让jvm上的新语言去实现(比如JRuby、Scala),java语言作为成熟的工业语言本身不应当做太大的改变。而着眼未来,也就是说新的语言特性应该为未来的语法扩展留有空间,它的语法/语义不应当跟现存的或者潜在的特性相冲突,以便可以持续地演化。再谈顾及当前的模型,一门语言代表着一种计算模型,比如simulaOO模型(classes)Erlang就是inter-process communication的模型(actor)。Java语言也有一个简单的模型:首先它是“高层”语言,是一门通用、并发、基于类的OO语言,其次,它跟APIJVM有良好的结合。Java语言模型有四个原则:

a)鼓励high-level实践,通过抽象来隐藏偶然复杂度。简而言之:do the right thing

b)追求清晰,程序被读的时候远远多于写。简而言之:do the thing right.

c)青睐静态类型,静态类型能增进对代码的信心,静态类型能证明bug在编译时的不存在,而测试和动态类型能证明bug的存在。我的观点是,大多数难以寻找和解决的bug都是runtime的,静态类型在此方面能给出的帮助有限,充分并且适宜的测试更加能增强你对应用的信心。

d)语言比之API的更广泛。one language,many apiAPI来去匆匆,而语言却是forever,因而将语言和API分离是明智的,一些特性可以做为库来实现,jdk5并发库的引入就很好,jdk7在并发方面同样将引入fork/join模型。

java语言的演化也当遵循这四个原则。再看看传说中的闭包语言,当它跟泛型结合的时候写出来的东西还谈得上清晰吗?闭包的实现能否解决兼容性问题也是个疑问。就四个提案,C3S需要引入method关键字(类似lambda),FCM的#号看起来比较怪异,在我看来,CICE和BGGA更符合胃口,CICE对java语言的变动应该最小,学习曲线也比较平缓,BGGA的=>符号更有函数式语言的味道。闭包的引入,某种程度上能减少敲击键盘的次数并实现一些高阶功能,特别是在聚合操作(如filter、map等)和单抽象方法类(如Runnable,Callable)的使用上,但是在现代IDE的自动化帮助下,这个带来的价值是值的怀疑的。




posted @ 2008-06-18 00:20 dennis 阅读(2054) | 评论 (0)编辑 收藏

仅列出标题
共56页: First 上一页 24 25 26 27 28 29 30 31 32 下一页 Last