中国java开源文档大全
java教程,java开源文档大全
java教程,java开源文档大全
首页 java基础 web开发框架 开发工具 应用系统 组件类库 搜索爬虫 J2EE服务器 持久层相关 测试工具 访客留言 投稿专栏 站内搜索
java教程,java开源文档大全
>首页 -> 组件类库 -> AOP -> Spring 2.5

TOP

Spring 2.5 Perfomance Improvements
[ 录入者:admin | 时间:2007-12-08 06:23:26 | 作者: | 来源:原创 | 浏览:17次 ]
  java开源文档大全致力于打造中国最大最全的开源文档,它提供了最全面最权威的开源资料,同时为大家提供一个交流的平台,如果您有好的想法,欢迎您投稿.


The upcoming Spring Framework version 2.5 will bring a 200% improvement for concurrent access over Spring 2.0.*. I used Crazy Bob's Semi Useless Benchmark ™ as a starting point. I fiddled with the code slightly to change the default behavior from "prototype" to "singleton", and I saw that spring 2.5 was faster than Guice for singletons.

Here are some benchmarks (there is variability based on the runs)

  • Spring 2.0 vs. guice 1.0:
    • Prototype: Single thread: Spring is 50-150X slower. Concurrent: Spring is 50-150X slower.
    • Singleton: Single thread: Spring 3X slower - 2X faster. Concurrent: Spring is 5-10X slower
  • Spring 2.0.6 vs. guice 1.0:
    • Prototype: Single thread: Spring is ~10X slower. Concurrent: Spring is 5X slower.
    • Singleton: Single thread: Spring 2X slower - 2X faster. Concurrent: Spring:Guice ~2:3
  • Spring 2.14m vs. guice 1.0:
    • Prototype: Single thread: Spring is 5-7X slower. Concurrent: Spring is 3-4X slower.
    • Singleton: Single thread: neck and neck. Concurrent: Spring is 1-1.5X faster
  • guice 1.0:
    • Prototype: Single thread vs. Concurrent: Concurrent might be a bit slower than single threaded
    • Singleton: Single thread vs. Concurrent: Concurrent is quite a bit faster than single threaded

One of the reasons for the concurrent performance improvements is the use of a ConcurrentHashMap that has much better concurrency handling than the vanilla synchronized blocks found in the plain old Collections.synchronized(new HashMap()). You get this performance improvements out-of-the-box if you use JDK 5.0+ or if you add the Emory concurrent utilities backport to your classpath.

There still is room for improvement for "core" BeanFactory functionality, but overall, the Spring team has done an excellent job at continual performance improvements. I'm sure that Guice has had performance improvements since it's 1.0 release, but I'm more concerned with Spring which is my bread-and-butter at my day job. What I do have to say about Guice is that it definitely provided motivation for furthering technolog...

Guice is still a lot faster than Spring for prototypes. I'm not 100% sure where the bottlenecks are, but I would say two things about prototypes:

  1. Make them faster: Their lifecycle dynamics are different than singletons, they need to be treated as such, although I don't have concrete solutions to this issue.
  2. Think in prototypes: Guice treats prototypes as a first level citizen... Spring doesn't. Why is that? Could it be that most enterprise systems don't really need complex IoC for prototype objects?

One last bit of info before I end this... When working with prototypes what do you think is faster in Spring:

  1. references to other fully managed prototype beans.
  2. nested <bean> beans?

Unfortunately that answer is references to other prototype beans... check it out yourself.

Update: here's the code:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.DecimalFormat;
import java.util.concurrent.Callable;

import junit.framework.TestCase;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Scopes;
import com.google.inject.Singleton;

public class SpringPerformanceTest extends TestCase {

    public static void main(String[] args) throws Exception {
        // Once warm up. Takes lazy loading out of the equation and ensures we
        // created the graphs properly.
        validate(springFactory, false);
        validate(juiceFactory, false);
        validate(byHandFactory, false);

        System.err.println("===================================");
        System.err.println("Prototypes :");
        System.err.println("===================================");

        System.err.println("======");
        System.err.println("Concurrent:");
        System.err.println("======");

        for (int i2 = 0; i2 < 5; i2++) {
            concurrentlyIterate(springFactory, "Spring: ", false);
            concurrentlyIterate(juiceFactory, "Guice:   ", false);
            concurrentlyIterate(byHandFactory, "By Hand: ", false);

            System.err.println();
        }

        System.err.println("======");
        System.err.println("Single Threaded:");
        System.err.println("======");

        for (int i2 = 0; i2 < 5; i2++) {
            iterate(springFactory, "Spring: ", false);
            iterate(juiceFactory, "Guice:   ", false);
            iterate(byHandFactory, "By Hand: ", false);

            System.err.println();
        }

        System.err.println("===================================");
        System.err.println("SingleTons :");
        System.err.println("===================================");

        System.err.println("======");
        System.err.println("Concurrent:");
        System.err.println("======");

        for (int i2 = 0; i2 < 5; i2++) {
            concurrentlyIterate(springSingletonFactory, "Spring: ", true);
            concurrentlyIterate(juiceSingletonFactory, "Guice:   ", true);
            concurrentlyIterate(byHandSingletonFactory, "By Hand: ", true);

            System.err.println();
        }

        System.err.println("Single:");

        for (int i2 = 0; i2 < 5; i2++) {
            iterate(springSingletonFactory, "Spring: ", true);
            iterate(juiceSingletonFactory, "Guice:   ", true);
            iterate(byHandSingletonFactory, "By Hand: ", true);

            System.err.println();
        }

    }

    public static class SpringCallable implements Callable<Foo> {

        final BeanFactory beanFactory;

        public SpringCallable(boolean isSingleton) {
            beanFactory = getBeanFactory(isSingleton);
        }

        public Foo call() throws Exception {
            return (Foo) beanFactory.getBean("foo");
        }
    }

    static final Callable<Foo> springFactory = new SpringCallable(false);

    static final Callable<Foo> springSingletonFactory = new SpringCallable(true);

    public static BeanFactory getBeanFactory(boolean isSingleton) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        RootBeanDefinition tee = new RootBeanDefinition(TeeImpl.class, true);
        tee.setLazyInit(true);
        ConstructorArgumentValues teeValues = new ConstructorArgumentValues();
        teeValues.addGenericArgumentValue("test");
        tee.setConstructorArgumentValues(teeValues);

        RootBeanDefinition bar = new RootBeanDefinition(BarImpl.class, isSingleton);
        ConstructorArgumentValues barValues = new ConstructorArgumentValues();
        barValues.addGenericArgumentValue(new RuntimeBeanReference("tee"));
        barValues.addGenericArgumentValue(5);
        bar.setConstructorArgumentValues(barValues);

        RootBeanDefinition foo = new RootBeanDefinition(Foo.class, isSingleton);
        MutablePropertyValues fooValues = new MutablePropertyValues();
        fooValues.addPropertyValue("i", 5);
        fooValues.addPropertyValue("bar", new RuntimeBeanReference("bar"));
        fooValues.addPropertyValue("copy", new RuntimeBeanReference("bar"));
        fooValues.addPropertyValue("s", "test");
        foo.setPropertyValues(fooValues);

        beanFactory.registerBeanDefinition("foo", foo);
        beanFactory.registerBeanDefinition("bar", bar);
        beanFactory.registerBeanDefinition("tee", tee);
        return beanFactory;
    }

    static final Callable<Foo> juiceFactory = new Callable<Foo>() {
        final Provider<Foo> fooProvider;
        {
            Injector injector;
            try {
                injector = Guice.createInjector(new AbstractModule() {
                    protected void configure() {
                        bind(Tee.class).to(TeeImpl.class);
                        bind(Bar.class).to(BarImpl.class);
                        bind(Foo.class);
                        bindConstant().annotatedWith(I.class).to(5);
                        bindConstant().annotatedWith(S.class).to("test");
                    }
                });
            } catch (CreationException e) {
                throw new RuntimeException(e);
            }
            fooProvider = injector.getProvider(Foo.class);
        }

        public Foo call() throws Exception {
            return fooProvider.get();
        }
    };

    static final Callable<Foo> juiceSingletonFactory = new Callable<Foo>() {
        final Provider<Foo> fooProvider;
        {
            Injector injector;
            try {
                injector = Guice.createInjector(new AbstractModule() {
                    protected void configure() {
                        bind(Tee.class).to(TeeImpl.class);
                        bind(Bar.class).to(BarImpl.class).in(Scopes.SINGLETON);
                        bind(Foo.class).in(Scopes.SINGLETON);
                        bindConstant().annotatedWith(I.class).to(5);
                        bindConstant().annotatedWith(S.class).to("test");
                    }
                });
            } catch (CreationException e) {
                throw new RuntimeException(e);
            }
            fooProvider = injector.getProvider(Foo.class);
        }

        public Foo call() throws Exception {
            return fooProvider.get();
        }
    };

    private static class ByHandFactory implements Callable<Foo> {

        private boolean isSingleton;

        final Tee tee = new TeeImpl("test");
        final Foo foo;

        public ByHandFactory(boolean isSingleton) {
            this.isSingleton = isSingleton;
            foo = isSingleton ? createFoo() : null;
        }

        public Foo call() throws Exception {
            if (isSingleton)
                return foo;
            else
                return createFoo();
        }

        private Foo createFoo() {
            Foo foo = new Foo();
            foo.setI(5);
            foo.setS("test");
            Bar bar = new BarImpl(tee, 5);
            Bar copy = isSingleton ? bar : new BarImpl(tee, 5);
            foo.setBar(bar);
            foo.setCopy(copy);
            return foo;
        }

    };

    static final Callable<Foo> byHandFactory = new ByHandFactory(false);
    static final Callable<Foo> byHandSingletonFactory = new ByHandFactory(true);

    static void validate(Callable<Foo> t, boolean isSingleton) throws Exception {
        Foo foo = t.call();
        assertEquals(5, foo.i);
        assertEquals("test", foo.s);
        Bar bar = foo.bar;
        Bar copy = foo.copy;
        assertSame(bar.getTee(), copy.getTee());
        if (isSingleton) {
            assertSame(bar, copy);
        } else {
            assertNotSame(bar, copy);
        }
        assertEquals(5, bar.getI());
        assertEquals("test", bar.getTee().getS());
    }

    static final DecimalFormat format = new DecimalFormat();

    static void iterate(Callable<Foo> callable, String label, boolean isSingleton) {
        iterate(callable, label, 1, isSingleton);
    }

    private static long concurrentTime = 0;

    static void concurrentlyIterate(final Callable<Foo> callable, String label, boolean isSingleton) {
        iterate(callable, label, 5, isSingleton);
    }

    private static void iterate(final Callable<Foo> callable, String label, int threadCount, final boolean isSingleton) {
        final long count = isSingleton ? 100000 : 10000;

        concurrentTime = 0;
        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++) {
            threads[i] = new Thread() {
                public void run() {
                    long testStart = System.currentTimeMillis();
                    for (int i = 0; i < count; i++) {
                        try {
                            validate(callable, isSingleton);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                    synchronized (SpringPerformanceTest.class) {
                        concurrentTime += (System.currentTimeMillis() - testStart);
                    }
                }
            };
        }

        for (int i = 0; i < threadCount; i++) {
            threads[i].start();
        }

        for (int i = 0; i < threadCount; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        if (concurrentTime == 0) {
            System.err.println(label + " is too freaking fast");
        } else {
            long total = count * threadCount * threadCount * 1000 / concurrentTime;
            System.err.println(label + format.format(total) + " creations/s");
        }
    }

    public static class Foo {

        Bar bar;
        Bar copy;
        String s;
        int i;

        @Inject
        public void setI(@I
        int i) {
            this.i = i;
        }

        @Inject
        public void setBar(Bar bar) {
            this.bar = bar;
        }

        @Inject
        public void setCopy(Bar copy) {
            this.copy = copy;
        }

        @Inject
        public void setS(@S
        String s) {
            this.s = s;
        }
    }

    interface Bar {

        Tee getTee();

        int getI();
    }

    public static class BarImpl implements Bar {

        final int i;
        final Tee tee;

        @Inject
        public BarImpl(Tee tee, @I
        int i) {
            this.tee = tee;
            this.i = i;
        }

        public Tee getTee() {
            return tee;
        }

        public int getI() {
            return i;
        }
    }

    interface Tee {

        String getS();
    }

    @Singleton
    public static class TeeImpl implements Tee {

        final String s;

        @Inject
        public TeeImpl(@S
        String s) {
            this.s = s;
        }

        public String getS() {
            return s;
        }
    }

    @Retention(RetentionPolicy.RUNTIME)
    @BindingAnnotation
    @interface I {
    }

    @Retention(RetentionPolicy.RUNTIME)
    @BindingAnnotation
    @interface S {
    }
}

Update 2: The latest Guice code definitely performs better, but as Bob Lee says in one of the comments bellow, there still is a bottleneck caused by a call to ThreadLocal. Moral of the story: stay away from ThreadLocals and Collections.synchronizedMap if you want better performance :).



  java开源文档研究struts,webwork,spring,tomcat,jboss,lucense,nutch,JUnit,eclipse......,如果您有什么意见,欢迎评论和留言.
<< < 1 2 > >> 2/2
[下一篇]Spring 2.0的新特性点评 [上一篇]Spring 2.5 下载并非"完全&q..

评论

称  呼:
内  容:

google

相关栏目

最新文章

热门文章

推荐文章

更多友情链接>>>