庄周梦蝶

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


来源:http://moonbase.rydia.net/mental/blog/programming/the-biggest-mistake-everyone-makes-with-closures.html

看下面的Ruby代码
= []
for x in 1..3
  k.push(
lambda { x })
end

执行
k[0].call

你可能预期返回1,实际的结果却是3。这是为何?这是因为在迭代过程中共用了同一个context,导致k中的三个闭包都引用了同一个变量x。不仅仅Ruby有这个问题,python也一样
= [lambda: x for x in xrange(14)]
k[0]()

Javascript同样如此

var k = [];
for (var x = 1; x < 4; x++) {
  k.push(function () { 
return x; });
}
alert(k[0]())


解决这个问题很简单,就是将闭包包装到一个函数里,建立新的context,那么迭代过程中生成的闭包所处的context不同:
def make_value_func(value)
  
lambda { value }
end
= (1..3).map { |x| make_value_func(x) }

这个时候,k[0].call正确地返回1。

这个问题并非在所有支持闭包的语言里都存在,例如scheme中就没有问题

(define k '())
(do ((x 1 (+ x 1)))
    ((
= x 4'())
  (set! k (cons (lambda () x) k)))
(set! k (reverse k))

((car k)) 
=>1


Erlang也没有问题
K=[ fun()->X end || X <- [1,2,3]].

lists:map(fun(F)
-> F() end,K).

再试试Clojure:
(def k (for [i (range 1 4)] (fn [] i)))
(map #(
%) k)

同样没有问题。这里Erlang和Clojure都采用列表推断。




posted @ 2010-07-09 23:52 dennis 阅读(1718) | 评论 (4)编辑 收藏

    一些常见的关于xmemcached的问题,收集整理,集中解答在此。事实上这里的大部分问题都可以在用户指南里找到。

一、XMemcached是什么?
经常碰到的一个问题是很多朋友对memcached不了解,误以为xmemcached本身是一个缓存系统。Memcached是一个开源的,C写的分布式key-value缓存,XMemcached只是它的一个访问客户端。Memcached通过网络协议跟客户端交互,通过客户端你才可以去使用memcached,xmemcached是它的java客户端之一。

二、为什么要选择xmemcached?

memcached的java客户端有多个选择,为什么要选择xmemcached?理由如下:

1、支持所有的文本协议和二进制协议,支持连接KestrelTokyoTyrant等memcached协议兼容的系统并作特殊处理。
2、支持动态添加和删除memcached节点。
3、支持客户端统计
4、支持JMX监控和统计,可以通过JMX增删节点。
5、高性能
6、支持节点的权重设置
7、支持nio的连接池,在高负载环境下提高吞吐量。

三、对jdk版本有什么要求?

Xmemcached仅支持jdk1.5及以上版本。

四、使用的时候需要创建多个MemcachedClient对象吗?MemcachedClient是不是线程安全?

MemcachedClient是线程安全的,由于xmemcached的网络层实现是基于nio长连接的,因此你并不需要重复创建多个MemcachedClient对象,通常来说将MemcachedClient设置为全局的唯一单例的服务使用,如果是使用spring配置,那更是简单,在spring配置文件里配置一个MemcachedClient,其他对象引用即可使用。

五、为什么会抛出java.util.TimeoutException?

这是由于xmemcached的通讯层是基于非阻塞IO的,那么在请求发送给memcached之后,需要等待应答的到来,这个等待时间默认是1秒,如果超过1秒就抛出java.util.TimeoutExpcetion给用户。如果你频繁抛出此异常,可以尝试将全局的等待时间设置长一些,如我在压测中设置为5秒:
MemcachedClient  memcachedClient=……
memcachedClient.setOpTimeout(
5000L);

请注意,setOpTimeout设置的是全局的等待时间,如果你仅仅是希望将get或者set等操作的超时延长一点,那么可以通过这些方法的重载方法来使用:
<T> T get(java.lang.String key,long timeout)

boolean set(java.lang.String key, int exp,java.lang.Object value,
            
long timeout)

……


六、Kestrel和TokyoTyrant不支持flag字段,xmemcached是怎么解决的?

Xmemcached在存储的value前面自动加上和去除4个字节的flag,这一切对应用来说是透明的。具体请看用户指南。


七、连接memcacheq,取出来的消息比放进去的多?


这是由于memcacheq和kestrel一样,不支持multi get协议,因此只要关闭xmemcached的multi get优化就可以了。

memcachedClient.setOptimizeGet(false);

所谓multi get优化是指xmemcached会将连续的单个get请求合并成一个multi get请求作批量获取,提高效率。

八、连接kestrel,为什么过一段时间会自动断开并重连?

你可能使用的是kestrel 1.2以下版本,kestrel 1.2才支持version协议,xmemcached是基于version协议做心跳检测,因此当使用kestrel 1.2以下版本的时候会发生心跳检测失败并断开连接重连的情况,你可以升级kestrel,也可以关闭心跳检测:

memcachedClient.setEnableHeartBeat(false);

九、我使用maven,怎么引用xmemcached?

xmemcached 1.2.5已经加入了maven的中心仓库,因此你可以直接引用
  <dependency>
      
<groupId>com.googlecode.xmemcached</groupId>
      
<artifactId>xmemcached</artifactId>
      
<version>1.2.5</version>
 
</dependency>

如果是之前版本,我推荐你升级,或者自己手工加入私人的maven仓库。

十、连接池是怎么回事?设置多大为好?

在高负载环境下,nio的单连接也会遇到瓶颈,此时你可以通过设置连接池来让更多的连接分担memcached的请求负载,从而提高系统的吞吐量。设置连接池通过
MemcachedClientBuilder builder = new    XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000"));

builder.setConnectionPoolSize(
5);
MemcachedClient client
=builder.build();

或者通过spring配置也可以。

连接池通常不建议设置太大,我推荐在0-30之间为好,太大则浪费系统资源,太小无法达到分担负载的目的。

十一、性能建议及优化手段

    性能的调整只能给出一般性的原则,实际情况千差万别,每次调整都需要做实际的测量才能确定是否带来期望的效果。

1、如果你的数据较小,如在1K以下,默认的配置选项已经足够。如果你的数据较大,我会推荐你调整网络层的TCP选项,如设置socket的接收和发送缓冲区更大,启用Nagle算法等等:   
            MemcachedClientBuilder builder = new XMemcachedClientBuilder(
                    AddrUtil.getAddresses(servers));
            builder.setSocketOption(StandardSocketOption.SO_RCVBUF, 
32 * 1024); // 设置接收缓存区为32K,默认16K
            builder.setSocketOption(StandardSocketOption.SO_SNDBUF, 16 * 1024); // 设置发送缓冲区为16K,默认为8K
            builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false); // 启用nagle算法,提高吞吐量,默认关闭

默认如果连接超过5秒没有任何IO操作发生即认为空闲并发起心跳检测,你可以调长这个时间: 
  builder.getConfiguration().setSessionIdleTimeout(10000);  // 设置为10秒;

更多网络层配置选项请参见Configuration类。

2、Xmemcached默认会做两个优化:将连续的单个get合并成一个multi get批量操作获取,将连续的请求合并成socket发送缓冲区大小的buffer发送。
如果你对响应时间比较在意,那么可以将合并的因子减小,或者关闭合并buffer的优化:
    memcachedClient.setMergeFactor(50);   //默认是150,缩小到50
    memcachedClient.setOptimizeMergeBuffer(false);  //关闭合并buffer的优化

如果你对吞吐量更在意,那么也可将合并因子调大,默认是150。但是也不可太大,太大可能导致平均响应时间延长。

3、如果你对心跳检测不在意,也可以关闭心跳检测,减小系统开销
memcachedClient.setEnableHeartBeat(false);
这个关闭,仅仅是关闭了心跳的功能,客户端仍然会去统计连接是否空闲,禁止统计可以通过:
builder.getConfiguration().setStatisticsServer(false);





posted @ 2010-07-08 18:37 dennis 阅读(20442) | 评论 (35)编辑 收藏

   让你不带萨队,让你不带坎比亚所,我太他妈高兴了。
   布尔迪索、德米凯利斯这样的著名漏勺,还有古铁雷斯这样的牛B后卫,想进决赛完全在做梦。
   什么艺术足球,什么功利足球,看看德国队的配合,脸红不?
   只会在弱队身上刷数据到伊瓜因,给米利托擦鞋都不配。
   梅球王被吹捧得太多了,相对于真小人的C罗,小动作、下阴招的梅球王终于带着0进球到记录回家了。88,阿根廷,世界清净了。当然,马上有一帮恶心阿迷矫情地唱着“阿根廷别为我哭泣”为他们的“潘帕斯雄鹰”招魂呢。


  

posted @ 2010-07-04 00:08 dennis 阅读(787) | 评论 (0)编辑 收藏

     摘要:     《飞行大亨》是我很喜欢的一部电影,不过这里我想介绍的是一个叫Aviator的开源的Java表达式求值器。 一、轮子的必要性     表达式的求值上,java的选择非常多,强大的如Groovy、JRuby,N年没维护的beanshell,包括javaeye上朋友的IKExpression。为什么还需要Aviator?或者说Avi...  阅读全文

posted @ 2010-06-29 11:44 dennis 阅读(21978) | 评论 (15)编辑 收藏

Java memcached客户端——XMemcached发布1.2.5版本,这是1.2的最后一个小版本,主要的改进如下:

1、合并yanf4j到xmemcached,目前只是简单的源码合并,以及去除了不需要的udp支持。因此从1.2.5开始,xmemcached不再依赖yanf4j,仅依赖slf4j

2、支持SASL验证。memcached 1.4.3新增了SASL授权特性,启用了SASL的memcached会要求客户端进行授权验证,否则将拒绝请求,对于需要验证的用户来说是个可选的特性,关于memcached的SASL支持更多请看这里Xmemcached 1.2.5开始支持客户端的SASL验证,一个典型的使用例子如下:

        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
                                        AddrUtil.getAddresses(
"localhost:11211"));
        builder.addAuthInfo(AddrUtil.getOneAddress(
"localhost:11211"), AuthInfo
                                        .typical(
"cacheuser""123456"));
        
// Must use binary protocol
        builder.setCommandFactory(new BinaryCommandFactory());
        MemcachedClient client
=builder.build();

 

3、加快MemcachedClient.shutdown()方法的速度,应用可以更快地关闭xmemcached。

4、完善中文用户指南,添加客户端分布和SASL验证两节。

   如果你使用maven,1.2.5已经放入maven的中心仓库,因此添加依赖即可使用:

 <dependency>
       
<groupId>com.googlecode.xmemcached</groupId>
       
<artifactId>xmemcached</artifactId>
       
<version>1.2.5</version>
  
</dependency>


更多信息请参见wiki和changelog

XMemcached是一个基于java nio的memcached客户端

项目主页:  http://code.google.com/p/xmemcached/

下载地址: http://code.google.com/p/xmemcached/downloads/list

wiki地址:http://code.google.com/p/xmemcached/w/list

posted @ 2010-06-22 18:17 dennis 阅读(3505) | 评论 (2)编辑 收藏



一、传统并发模型的缺点


基于线程的并发


特点:
每任务一线程
直线式的编程
使用资源昂高,
context切换代价高,竞争锁昂贵
太多线程可能导致吞吐量下降,响应时间暴涨。

基于事件的并发模型



特点:
单线程处理事件
每个并发流实现为一个有限状态机
应用直接控制并发
负载增加的时候,吞吐量饱和
响应时间线性增长


二、SEDA架构




特点:
(1)服务通过queue分解成stage:
   每个stage代表FSM的一个状态集合
   Queue引入了控制边界
(2)使用线程池驱动stage的运行:
   将事件处理同线程的创建和调度分离
   Stage可以顺序或者并行执行
   Stage可能在内部阻塞,给阻塞的stage分配较少的线程

1、Stage-可靠构建的基础



(1)应用逻辑封装到Event Handler
   接收到许多事件,处理这些事件,然后派发事件加入其他Stage的queue
   对queue和threads没有直接控制
   Event queue吸纳过量的负载,有限的线程池维持并发
(2)Stage控制器
  负责资源的分配和调度
  控制派发给Event Handler的事件的数量和顺序
  Event Handler可能在内部丢弃、过滤、重排序事件。

2、应用=Stage网络

   (1)有限队列
        入队可能失败,如果队列拒绝新项的话
        阻塞在满溢的队列上来实现吸纳压力
        通过丢弃事件来降低负载
   (2) 队列将Stage的执行分解
        引入了显式的控制边界
        提供了隔离、模块化、独立的负载管理
   (3)方便调试和profile
        事件的投递可显
        时间流可跟踪
        通过监测queue的长度发现系统瓶颈

3、动态资源控制器

(1)、线程池管理器

目标: 决定Stage合理的并发程度
操作:
观察queue长度,如果超过阀值就添加线程
移除空闲线程



(2)、批量管理器
目的:低响应时间和高吞吐量的调度
操作:
Batching因子:Stage一次处理的消息数量
小的batching因子:低响应时间
大的batching因子:高吞吐量

尝试找到具有稳定吞吐量的最小的batching因子
观察stage的事件流出率
当吞吐量高的时候降低batching因子,低的时候增加


三、小结
   SEDA主要还是为了解决传统并发模型的缺点,通过将服务器的处理划分各个Stage,利用queue连接起来形成一个pipeline的处理链,并且在Stage中利用控制器进行资源的调控。资源的调度依据运行时的状态监视的数据来进行,从而形成一种反应控制的机制,而stage的划分也简化了编程,并且通过queue和每个stage的线程池来分担高并发请求并保持吞吐量和响应时间的平衡。简单来说,我看中的是服务器模型的清晰划分以及反应控制。



  

posted @ 2010-06-20 23:53 dennis 阅读(7265) | 评论 (6)编辑 收藏

    Java的垃圾收集算法是分代的,因为根据2/8原则,80%的Java对象都是速生速灭的,因此将Java Heap划分为new和old,对两个区域采用不同的垃圾回收算法,在new代存活下来的对象转移到old区,这样一来大大提高了Java GC的效率。
    类似分代的思想在很多地方可以用到,分代的本质是根据对象生命周期的不同做区别处理,而不是采取一刀切的方式来提高系统的处理效率。推而广之,比如缓存的使用,现在很多web应用都采用了类似memcached这样的缓存挡在数据库前面分担负载,那么你可以将memcached理解成new代,而数据库是old代。memcached中存储的是查询的热点数据,新鲜火热,但是易失,并且在数据更新的时候被移除;而数据库保存了所有的数据,当缓存没有命中的时候才去查询数据库并存储到缓存。new和old这只是简单的二代划分,事实上现在越来越多的系统是多级缓存,页面缓存、memcached缓存、JVM内部缓存、查询缓存等等直到数据库,从web页面到后端是一个越来越old的过程,缓存对象持续的生命周期逐渐增长直到persist状态。
    具体到JVM内部缓存,我们通常使用LRU算法来实现一个安全有限的缓存,如直接继承LinkedHashMap将可以实现一个简单的LRUMap。基于内存使用上的考虑,我们会给LRUMap设定一个最大的capacity,当数据量超过这个capacity的时候将最近最少访问的元素移除来容纳新的元素。这样处理产生的问题是这个capactity不能设置得太大,因为怕内存不够用,但是不够大的结果可能是命中率没有那么高(跟你的场景相关),那么如何在保存内存安全的前提下更进一步缓存更多的对象呢?答案也是分代。LRUMap默认存储的都是对象的强引用,我们知道Java还有其他3种引用类:soft,weak和phantom。其中Soft引用是在jvm内存不够的时候进行回收,weak引用是在垃圾回收碰到的时候会被回收,显然weak->soft->strong三类引用的生命周期可以划分为3个代,我们将可以实现一个可以容纳更多对象的LRUMap:LRUMap设置两个阀值,一个是强引用的最大阀值,这个不能太大,一个是软引用的最大数目,当超过第一个阀值的时候,不是将LRU替换出来的对象移除,而是替代转换为软引用存储;如果软引用的数目也超过阀值,那么可以将软引用这个Map里的对象LRU替换成Weak引用存储或者简单移除。处理元素查询的时候,多了一个步骤,在查询强引用未果的情况下,需要再去查询软引用集合,不过都是O(1)复杂度的查询,不会成为明显的瓶颈。通过将缓存对象分代,我们实现了容难更多缓存对象的目标,大部分对象以强引用的形式存储,被LRU替换出去最近最少访问的元素以软引用存储,它们在内存不够的时候被垃圾回收,保证了内存使用上的安全性。我们在系统中采用了类似这样的缓存,缓存的命中率有了明显的提高。
    题目是《缓存的分代》,其实谈的是分代这种常见的设计或者说技巧,在需要处理大量对象的场景中,不采用一刀切的方式,而是根据对象的特点进行适当的分代处理,带来的效率提升可能是惊人的。

    PS.关于这个招聘罗嗦两句,我是这个小组的成员,有人质疑我的目的是为了赚推荐费,这个不能说没有,不过主要目的还是招人,我们很缺人。那么多要求可以归结为一句话:我们找Java基础良好、对并发通信有丰富实践经验、写代码相对靠谱、为人相对靠谱的人。那些要求并非硬性,如果你觉的合适,尽管投简历,谢谢。我们小组做的东西我认为还是有价值的,也很有挑战,淘宝内部的很多应用都在使用,如果你希望你做的产品被成千上万的人每天使用,欢迎加入。

     

   

posted @ 2010-06-05 10:13 dennis 阅读(4504) | 评论 (5)编辑 收藏

    作为一个coder,我不仅在写程序,也在写bug。遇到bug总是比较尴尬的事情,如果这个bug还是别人发现,那更是心里不好受。责备自己是没有用的,能做的是建立一个BUG数据库,时常回顾下自己犯过那些愚蠢的事情,怎么避免以后再犯同样的事情。昨天读《程序员》看到一笑话,说优秀的程序员哪怕在过单行道的时候也会向左右两边看,笑话其实不好笑,反而再次提醒我:小心、小心、再小心。
    毫不惭愧地说,我也是今年才开始有意识地去做回顾bug这件事情,今天回顾下最近写出来的这几个BUG:三个是麻痹大意导致的,一个是switch语句竟然没写break,一个是并发BUG,一个是考虑问题不全面导致的问题。这里主要还是想讲那三个麻痹大意写出来的BUG,都是在急匆匆修改问题的情况下写出来的,本意是为了解决原有的BUG,在自以为很有信心地情况下匆忙地修改代码,没有认真做review,没有添加单元测试,在解决问题的同时引入了新的问题。
    这些愚蠢的BUG修正起来非常简单,但是为什么那个时候却没有发现呢?我自省下,还是盲目自信导致的,因为快速地修复BUG似乎很能给人一种虚假的快感:瞧,这个问题我修正起来很快,我是代码快枪手,哦耶~,修复也还罢了,如果能再补充下测试,也许这些问题就能避免,但是我却又一次自信过了头。我在想,如果下次还遇到这种需要快速修改问题的时候我该怎么做,我该先深呼吸下,停一停,先想想怎么改再动手,想想风险点,改完之后至少review三遍,并且一定要添加这些情况的测试。尽管我相信以后我还会写下一些愚蠢的BUG,但是希望能让自己少后悔一点点。

posted @ 2010-06-05 01:06 dennis 阅读(1098) | 评论 (0)编辑 收藏

联系邮箱: boyan@taobao.com
简历格式: 最好是纯文本格式

淘宝分布式产品组诚聘Java工程师,有兴趣的请联系,谢谢,此招聘长期有效。具体职位和要求如下:

消息中间件资深Java工程师
工作地点:杭州
职位描述:
负责消息中间件的设计、开发等工作

职位要求:
1、扎实的Java开发基础知识
2、Java多线程、并发以及网络通信有深厚的经验
3、熟悉大规模分布式系统架构,熟悉分布式存储系统
4、热爱技术,对技术有不懈的追求。
5、熟悉消息中间件,并了解消息中间件原理的优先考虑

分布式数据层资深Java工程师
工作地点:杭州
职位描述:
负责分布式数据层的设计、开发等工作

职位要求:
1、扎实的Java开发基础知识
2、Java多线程、并发以及网络通信有深厚的经验
3、对JDBC,JPA,JTA有深厚的理解
4、熟悉常见的分布式存储解决方案
5、热爱技术,对技术有不懈的追求
6、熟悉数据层的原理和应用
7、熟悉关系数据库模型、有分布式事务相关经验优先

Java框架和工具开发工程师
工作地点:杭州
职位描述:
1、 设计、开发、改进基于Java的工具和框架。
2、 指导开发团队使用工具和框架,解决疑难问题。

职位要求:
1、 熟悉并自如运用Java语言及JDK类库,具备良好的编程习惯。
2、 熟悉多种Java开源项目,精通目前主流的Java开源项目的使用方法和设计理念。有独到见解者更佳。
3、 熟悉OOP理念及常见设计模式。
4、 熟悉Eclipse开发平台,了解Eclipse Plugin的开发。
5、 视野广阔,了解业内发展动态。
6、 喜爱专研,精益求精,有较强的学习能力。
7、 善于交流,乐于分享。
8、 具备英文阅读能力和书写能力。

应用管理工具开发工程师
工作地点:杭州
职位描述:
1、承担应用、系统管理工具及其他相关的工具、应用的开发
2、大规模应用管理相关技术的预研工作

职位要求:
1、两年及以上开发Java或Php开发经验
2、对技术充满兴趣,有扎实的编程基础
3、对经历过的产品、项目有深入的理解,而不仅停留在开发



联系邮箱: boyan@taobao.com
简历格式: 最好是纯文本格式

附注: 如果管理员觉的放在首页不合适,请拿下,不好意思,招人不容易啊。

posted @ 2010-06-03 16:05 dennis 阅读(5998) | 评论 (27)编辑 收藏

     每天下班后回家跟儿子的例行对话:

爸爸:你今天乖不乖?
儿子:啊
爸爸:有没有想爸爸?
儿子:啊
爸爸:吃饭了没?
儿子:哦
爸爸:有没有吃饱啊?
儿子:呃
……
     今天是儿童节,昨天晚上带小家伙去买玩具,儿子很替老爸省钱,自己只挑了气球。最后还是老爸老妈狠狠心给他买了画板和音乐小屋子,庆幸的是儿子很喜欢,一个晚上在那边“打电话”。儿子,节日快乐,希望你健康成长,快乐每一天。




posted @ 2010-06-01 11:18 dennis 阅读(1409) | 评论 (0)编辑 收藏

仅列出标题
共56页: First 上一页 8 9 10 11 12 13 14 15 16 下一页 Last