工作的几个tip
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。
上一篇: HDFS用户指南(翻译)