fastutilの注意点
WEB+DB PRESS Vol.60で、「fastutilとsuxによる大規模データ処理」と題して、プリミティブコレクションライブラリのfastutilと、簡潔データ構造ライブラリのsuxを紹介する記事を書きました。
- 作者: まつもとゆきひろ,西尾泰和,山田憲晋,城戸忠之,増井俊之,羽生章洋,uupaa,ミック,塙与志夫,原悠,奥一穂,はまちや2,大沢和宏,吾郷協,浜本階生,中島拓,中島聡,矢野りん,角田直行,能登信晴,田村哲也,吉村譲,結城亜砂子,角谷信太郎,石橋秀仁,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2010/12/22
- メディア: 大型本
- 購入: 12人 クリック: 185回
- この商品を含むブログ (24件) を見る
fastutil: http://fastutil.dsi.unimi.it/
sux: http://sux.dsi.unimi.it/
fastutilは特に汎用性が高く、いろいろな場面で使えるライブラリだと思うのですが、記事に挙げていない注意点も若干あるので、以下に書きたいと思います。
メソッド名の取り違えによる思わぬautoboxingの発生
fastutilでは、プリミティブリストはjava.util.Listと、プリミティブマップはjava.util.Mapと互換性を持っていて便利なのですが、その反面、get()メソッドがjava.util.List#get()やjava.util.Map#get()を実装しているため、何気なくget()メソッドを使うとautoboxingが発生してしまいます。
例えばIntArrayListには以下の2種類のgetメソッドがあり、プリミティブ値を直接取得するには後者のgetInt()メソッドを呼ぶ必要があります。
- Integer get(int index);
- int getInt(int index);
Mapのイテレーションが遅い
fastutilのパフォーマンスは、全体的にMahout CollectionsやTroveよりも優秀なのですが、Mapのイテレーションに関しては劣っています。
Mahout CollectionsやTroveのMap実装では、以下のように内部イテレータを使って高速なイテレーションができるのですが、fastutilにはそれがありません。
// Mahout Collectionsの場合 OpenIntIntHashMap map = new OpenIntIntHashMap(); ... map.forEachPair(new IntIntProcedure() { @Override public boolean apply(int key, int value) { // 何らかの処理 return true; } });
fastutilのマップで高速なイテレーションをしたい場合は、各マップクラスを継承して、内部イテレータを実装した方が良いと思います。
そこまでしたくないという場合、fastutilでは以下のようにfastIteratorという外部イテレータが使えます。記述が少し冗長になりますが、通常のイテレータよりは高速です。
Int2IntMap map = new Int2IntOpenHashMap(); ... Int2IntMap.FastEntrySet entrySet = (Int2IntMap.FastEntrySet) map.int2IntEntrySet(); ObjectIterator<Int2IntMap.Entry> it = entrySet.fastIterator(); while (it.hasNext()) { Int2IntMap.Entry e = it.next(); int key = e.getIntKey(); int value = e.getIntValue(); // 何らかの処理 }