そもそも設計思想が違うし、私は性能測定は素人だし、
使われる状況によっても結果はかわるしで、どこまでリアルなものかわかりませんが、LiQ Containerと Google Guice の性能を比較してみました。
テストケースは極めて単純で、Guiceのユーザガイドにのってる単純なインスタンス生成のコードを、LiQ とGuiceそれぞれで10万回繰り返す時間を測定する、というもの。
結果は下記の通り。
----
Guice Singleton:258ms
Guice PerLookup:289ms
LiQ PerLookup(Object Factory):213ms
LiQ PerLookup(Mapping):386ms
LiQ Singleton:213ms
----
JDK はMac OS X上の1.5.0_06, マシンはCore 2 Duo 1.83GHzのMacBookです。
Object Factoryとか、Mappingてのはなんじゃい、と思う方もおられると思いますが、とりあえずは設定方法の違いだと思ってください。
少なくとも単純なケースにおいては、Guiceに遜色ないパフォーマンスを出すことも可能だとわかって少し安心しました。
ただし、実はLiQは性能よりも柔軟性を重視して設計されているので、
設定が複雑になればなるほどLiQは性能的には不利だと思います。
でも、設定の手間は圧倒的に少ないはず。
LiQの世界ではいちいちModuleとかを書かなくても自動的にInjectできるケースが
ほとんどなのです。アピールしたいのは実は性能じゃないんですよね。
私としては、LiQがボトルネックになるような状況はそんなにはないよ、
ということがいえれば十分満足です。
それにしてもGuiceもLiQも毎回インスタンス生成するのと、
Singletonであまり性能が違わないんですねぇ。
あとは、同時実行性能も気になるところです。
いちおう今回のテストコード全文を貼付けておきます。
----
package jp.liq.vs.guice;
import jp.liq.container.Container;
import jp.liq.container.ContainerVocabulary;
import jp.liq.container.vocabulary.Factory;
import org.junit.Before;
import org.junit.Test;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Scope;
import com.google.inject.Scopes;
public class GuiceTest implements ContainerVocabulary {
public static interface Service {
}
public static class ServiceImpl implements Service {
}
public static class Client {
@Inject
public Client(Service service) {
}
}
public class SingletonModule implements Module {
public void configure(Binder binder) {
binder.bind(Service.class)
.to(ServiceImpl.class)
.in(Scopes.SINGLETON);
}
}
public class PerLookupModule implements Module {
public void configure(Binder binder) {
binder.bind(Service.class)
.to(ServiceImpl.class);
}
}
@Before
public void warmUpGuice() {
Injector injector = Guice.createInjector(new PerLookupModule());
for(int i = 0; i < 100000; i++) {
Client client = injector.getInstance(Client.class);
}
}
@Before
public void warmUpLiQ() {
Container container = new Container();
components.configure(container)
.define(component.instance(Service.class, new ServiceImpl()));
sentinel.configure(container);
for(int i = 0; i < 100000; i++) {
Client client = container.get(Client.class);
}
}
@Test
public void testGuiceSingleton() {
Injector injector = Guice.createInjector(new SingletonModule());
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
Client client = injector.getInstance(Client.class);
}
long end = System.currentTimeMillis();
System.out.println("Guice Singleton:" + (end - start));
}
@Test
public void testGuicePerLookup() {
Injector injector = Guice.createInjector(new PerLookupModule());
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
Client client = injector.getInstance(Client.class);
}
long end = System.currentTimeMillis();
System.out.println("Guice PerLookup:" + (end - start));
}
public class ServiceFactory {
@Factory
public Service createService() {
return new ServiceImpl();
}
}
@Test
public void testLiQObjectFactory() {
Container container = new Container();
components.configure(container)
.define(component.instance(Service.class, new ServiceImpl()));
sentinel.configure(container);
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
Client client = container.get(Client.class);
}
long end = System.currentTimeMillis();
System.out.println("LiQ PerLookup(Object Factory):" + (end - start));
}
@Test
public void testLiQMapping() {
Container container = new Container();
components.configure(container)
.define(component.mapping(Service.class, ServiceImpl.class));
sentinel.configure(container);
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
Client client = container.get(Client.class);
}
long end = System.currentTimeMillis();
System.out.println("LiQ PerLookup(Mapping):" + (end - start));
}
@Test
public void testLiQSingleton() {
Container container = new Container();
components.configure(container)
.define(component.instance(Service.class, new ServiceImpl()));
sentinel.configure(container);
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
Client client = container.get(Client.class);
}
long end = System.currentTimeMillis();
System.out.println("LiQ Singleton:" + (end - start));
}
}