DI&AOPパフォーマンス比較
明日のjava-ja@富山で、話すネタとして、DIContainerのパフォーマンス比較をしてみました。使ったのは、Spring, Guice, Seasar2.4, Slim3です。
DIのテストは、プロトタイプのBean同士のsetter injection。AOPのテストは、
何もせずにもとのメソッドを呼び出すだけの単純なものです。
使ったプロジェクトは、http://svn.slim3.org/browse/trunk/container-benchmark/においてあります。
結果はこんな感じ。
最初はDI。それぞれ10000回ループさせるテストを5回繰り返しています。
Slim3 DI: 319120167 nano
Seasar2 DI: 350858838 nano
Guice DI: 283541623 nano
Spring DI: 657129328 nano
-
-
- -
-
Slim3 DI: 9310960 nano
Seasar2 DI: 156790598 nano
Guice DI: 35546697 nano
Spring DI: 356141353 nano
-
-
- -
-
Slim3 DI: 9703748 nano
Seasar2 DI: 162930484 nano
Guice DI: 34984055 nano
Spring DI: 356262598 nano
-
-
- -
-
Slim3 DI: 9500369 nano
Seasar2 DI: 157047893 nano
Guice DI: 34867001 nano
Spring DI: 343818558 nano
-
-
- -
-
Slim3 DI: 9456230 nano
Seasar2 DI: 146980971 nano
Guice DI: 35360918 nano
Spring DI: 344662520 nano
-
-
- -
-
Slim3は、最初だけ遅いですが、後は速いですね。GuiceもSlim3には負けてますが、Seasar2やSpringよりも速い。Seasar2とSpringの差は2倍。まぁ、こんなもんでしょう。
次はAOP。それぞれ10000回ループさせるテストを5回繰り返しています。
Slim3 AOP: 20136917 nano
Seasar2 AOP: 6659785 nano
Guice AOP: 18718301 nano
Spring AOP: 65014129 nano
-
-
-
- -
-
-
Slim3 AOP: 12302681 nano
Seasar2 AOP: 4772394 nano
Guice AOP: 6979937 nano
Spring AOP: 6276496 nano
-
-
-
- -
-
-
Slim3 AOP: 6722642 nano
Seasar2 AOP: 4946438 nano
Guice AOP: 5509080 nano
Spring AOP: 7828369 nano
-
-
-
- -
-
-
Slim3 AOP: 6590782 nano
Seasar2 AOP: 4869613 nano
Guice AOP: 5534781 nano
Spring AOP: 7270477 nano
-
-
-
- -
-
-
Slim3 AOP: 1656355 nano
Seasar2 AOP: 3323328 nano
Guice AOP: 6633525 nano
Spring AOP: 6093791 nano
-
-
-
- -
-
-
Seasar2のAOPは、カリカリにチューニングされているだけあって、安定して速い。ただし、二回目以降は、それほどは差がついてません。
Slim3は、回数が増すごとにだんだん速くなってますね。さっきのDIも。理由は良くわかりません。コードが単純なので、VMが最適化しやすいのかもしれません。
明日は、これらの結果を踏まえて、ソースを見ながら、さらにAOPの実装の違いに触れます。東京ではやらないような濃いネタですが、こじんまりとした会だし、たまにはこういうのも楽しいでしょう。
最後に、それぞれのテストコードをのせて起きます。
package benchmark.main; import org.seasar.framework.container.ComponentDef; import org.seasar.framework.container.PropertyDef; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.deployer.InstanceDefFactory; import org.seasar.framework.container.impl.ComponentDefImpl; import org.seasar.framework.container.impl.PropertyDefImpl; import org.seasar.framework.container.impl.S2ContainerImpl; import org.slim3.container.S3Container; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import benchmark.action.FooAction; import benchmark.service.BarService; import com.google.inject.Guice; import com.google.inject.Injector; public class DIMain { private static final int COUNT = 10000; public static void main(String[] args) { for (int i = 0; i < 5; i++) { slim3(); seasar2(); guice(); spring(); System.out.println("----"); } } private static void slim3() { S3Container container = new S3Container(); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { container.lookup(FooAction.class); } System.out.printf("Slim3 DI:%10d nano\n", System.nanoTime() - start); } private static void seasar2() { S2Container container = new S2ContainerImpl(); ComponentDef cd = new ComponentDefImpl(FooAction.class, "fooAction"); cd.setInstanceDef(InstanceDefFactory.PROTOTYPE); PropertyDef pd = new PropertyDefImpl("barService"); cd.addPropertyDef(pd); ComponentDef cd2 = new ComponentDefImpl(BarService.class, "barService"); cd2.setInstanceDef(InstanceDefFactory.PROTOTYPE); container.register(cd); container.register(cd2); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { container.getComponent(FooAction.class); } System.out.printf("Seasar2 DI:%10d nano\n", System.nanoTime() - start); } private static void guice() { Injector injector = Guice.createInjector(); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { injector.getInstance(FooAction.class); } System.out.printf("Guice DI:%10d nano\n", System.nanoTime() - start); } private static void spring() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); RootBeanDefinition fooDef = new RootBeanDefinition(FooAction.class); fooDef.setScope("prototype"); MutablePropertyValues fooValues = new MutablePropertyValues(); fooValues.addPropertyValue("barService", new RuntimeBeanReference( "barService")); fooDef.setPropertyValues(fooValues); beanFactory.registerBeanDefinition("fooAction", fooDef); RootBeanDefinition barDef = new RootBeanDefinition(BarService.class); barDef.setScope("prototype"); beanFactory.registerBeanDefinition("barService", barDef); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { beanFactory.getBean("fooAction"); } System.out.printf("Spring DI:%10d nano\n", System.nanoTime() - start); } }
package benchmark.main; import static com.google.inject.matcher.Matchers.*; import org.seasar.framework.aop.impl.PointcutImpl; import org.seasar.framework.container.AspectDef; import org.seasar.framework.container.ComponentDef; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.deployer.InstanceDefFactory; import org.seasar.framework.container.impl.AspectDefImpl; import org.seasar.framework.container.impl.ComponentDefImpl; import org.seasar.framework.container.impl.S2ContainerImpl; import org.slim3.container.S3Container; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import benchmark.interceptor.SimpleInterceptor; import benchmark.service.Aop2Service; import benchmark.service.AopService; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; public class AOPMain { private static final int COUNT = 10000; public static void main(String[] args) throws Exception { for (int i = 0; i < 5; i++) { slim3(); seasar2(); guice(); spring(); System.out.println("-----"); } } private static void slim3() { S3Container container = new S3Container(); AopService service = container.lookup("aopService"); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { service.aaa(); } System.out.printf("Slim3 AOP:%10d nano\n", System.nanoTime() - start); } private static void seasar2() throws Exception { S2Container container = new S2ContainerImpl(); ComponentDef cd = new ComponentDefImpl(AopService.class, "barService"); cd.setInstanceDef(InstanceDefFactory.PROTOTYPE); AspectDef ad = new AspectDefImpl(new SimpleInterceptor(), new PointcutImpl(new String[] { "aaa" })); cd.addAspectDef(ad); container.register(cd); AopService service = (AopService) container .getComponent(AopService.class); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { service.aaa(); } System.out.printf("Seasar2 AOP:%10d nano\n", System.nanoTime() - start); } private static void guice() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bindInterceptor(only(Aop2Service.class), any(), new SimpleInterceptor()); } }); Aop2Service service = injector.getInstance(Aop2Service.class); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { service.aaa(); } System.out.printf("Guice AOP:%10d nano\n", System.nanoTime() - start); } private static void spring() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); RootBeanDefinition serviceDef = new RootBeanDefinition(AopService.class); beanFactory.registerBeanDefinition("aopService", serviceDef); RootBeanDefinition interceptorDef = new RootBeanDefinition( SimpleInterceptor.class); beanFactory.registerBeanDefinition("simpleInterceptor", interceptorDef); RootBeanDefinition proxyDef = new RootBeanDefinition( ProxyFactoryBean.class); proxyDef.setScope("prototype"); MutablePropertyValues proxyValues = new MutablePropertyValues(); proxyValues.addPropertyValue("target", serviceDef); proxyValues.addPropertyValue("interceptorNames", new String[] { "simpleInterceptor" }); proxyDef.setPropertyValues(proxyValues); beanFactory.registerBeanDefinition("proxy", proxyDef); AopService service = (AopService) beanFactory.getBean("proxy"); long start = System.nanoTime(); for (int i = 0; i < COUNT; i++) { service.aaa(); } System.out.printf("Spring AOP:%10d nano\n", System.nanoTime() - start); } }