java 板


LINE

※ 引述《dryman (dryman)》之铭言: : http://www.idryman.org/blog/2013/09/28/java-fast-io-using-java-nio-api/ : [略] 我也做了一些测试,来分享一下我的数据与观察。 说明: 以下使用一个 4*26Mb 内容为随机产生数值的档案作测试(M=K^2, K=1024, b=byte); method parameter 有名为 bufSize 者,实际测试时 actual argument=64K; 测试数据是以先跑 10 次要量测的 method,再跑 10 次取後十次的平均值; 这种测试方式应该会有 OS level cache 牵涉其中; 配合所使用的演算法,有些 method 测试时会提供 length 等於测试档案长度+64Kb 的 byte array。 我彷原作者的 startegy 2/3 的作法与数据如下: Record: 1096 ms Code: public static final void readAll(int[] arr, InputStream in, int bufSize) throws IOException { DataInputStream dataIn = new DataInputStream( new BufferedInputStream(in, bufSize)); try { for (int i = 0; i < arr.length; ++i) { arr[i] = dataIn.readInt(); } } finally { dataIn.close(); } } Record: 126 ms Code: public static final void readAllNIO(int[] arr, File input) throws IOException { FileChannel channel = new FileInputStream(input).getChannel(); try { ByteBuffer buffer = ByteBuffer.allocateDirect(64 * 1024); int offset = 0; int n; while ((n = channel.read(buffer)) != -1) { buffer.flip(); buffer.asIntBuffer().get(arr, offset, n >> 2); buffer.clear(); offset += n >> 2; } } finally { channel.close(); } } 不过严格来说 strategy 3(readAllNIO) 不十分正确,他假设了每次从 channel 作 read 操作所 consume 的 data size 为 4 的倍数。故其他的测试也会以这个 假设成立为前提(套用到 InputStream)。 我还做了其它的测试,我认为可以推论为 strategy 2 的瓶颈不在 IO 上: 假如只是把档案所有的 byte 读出到一个 byte array,一次读一区块,其实是蛮 快的。 Record: 78 ms Code: public static final void readAllBytes(byte[] arr, InputStream in) throws IOException { in = new BufferedInputStream(in, 64 * 1024); try { int n, offset = 0; while ((n = in.read(arr, offset, 64 * 1024)) != -1) offset += n; } finally { in.close(); } } 但稍作修改每次最多只读 4 bytes,大数量 iteration 里的运算会多耗很多时间, 约占了 readAll 的 7 成。 Record: 758 ms Code: public static final void readAllBytes3(byte[] arr, InputStream in) throws IOException { InputStream dataIn = new BufferedInputStream(in, 64 * 1024); int offset = 0; int n; try { while ((n = dataIn.read(arr, offset, 4)) != -1) { offset += n; } } finally { dataIn.close(); } } 采用 DataInputStream::readFully 来实作则更差一点。 Record: 940 ms Code: public static final void readAllBytes2(byte[] arr, InputStream in) throws IOException { DataInputStream dataIn = new DataInputStream( new BufferedInputStream(in, 64 * 1024)); int offset = 0; try { while (true) { dataIn.readFully(arr, offset, 4); offset += 4; } } catch (EOFException e) { } finally { in.close(); } } readAllNIO 的作法是一次读取一整块数据,一整块数据一批次 compose 成 int value(s),我想如果要公平一点,对照的 non-NIO 作法应该也要一次读 一整块,然後一整块批次作 composing。 我选择使用 nio Buffer 来实作的情况: Record: 820 ms Code: public static final void readAll2(int[] arr, InputStream in, int bufSize) throws IOException { InputStream dataIn = new BufferedInputStream(in, bufSize); byte[] block = new byte[bufSize]; int n, offset = 0; try { while ((n = dataIn.read(block)) != -1) { ByteBuffer.wrap(block, 0, n).asIntBuffer().get( arr, offset, n >> 2); offset += n >> 2; } } finally { dataIn.close(); } } 最後考虑到 readAllNIO 是使用 direct Buffer,或许 direct/non-direct Buffer 在 bulk get 的实作上(也许 native 层面)差别很大,於是我自己写了 native method 来作 composing 部分。 在 Windows 7 上以 sun 1.6.0_45 32-bits client VM 测试,由於处里器是 Little-endian,所以要处理 byte order 问题,若不处理 byte order 则可直接 使用 memcpy,那 performance 几乎与 readAllBytes 无异。 Record: 235 ms Code: public static final void readAll3(int[] arr, InputStream in, int bufSize) throws IOException { InputStream dataIn = new BufferedInputStream(in, bufSize); byte[] block = new byte[bufSize]; int n, offset = 0; try { while ((n = dataIn.read(block)) != -1) { arraycopy(block, 0, arr, offset, n >> 2); offset += n >> 2; } } finally { dataIn.close(); } } public static final void arraycopy(byte[] src, int srcOffset, int[] dest, int destOffset, int numsInt) { if (srcOffset + numsInt * 4 > src.length) throw new IllegalArgumentException("source array is too short"); if (destOffset + numsInt > dest.length) throw new IllegalArgumentException("destination array is too short"); arraycopyImpl(src, srcOffset, dest, destOffset, numsInt); } private static native void arraycopyImpl(byte[] src, int srcOffset, int[] dest, int destOffset, int numsInt); /* native method implementation */ #include <memory.h> #include <winsock2.h> #include "cc_ptt_java_IOSpeed.h" class PrimitiveArray { public: PrimitiveArray(JNIEnv *env, jarray arr, jint releaseMode) : _env(env), _array(arr), _mode(releaseMode), _address(0) { jboolean isCopy = JNI_FALSE; _address = env->GetPrimitiveArrayCritical(_array, &isCopy); } ~PrimitiveArray() { _env->ReleasePrimitiveArrayCritical(_array, _address, _mode); } operator jbyte *() const { return reinterpret_cast<jbyte *>(_address); } private: JNIEnv *_env; jarray _array; void* _address; jint _mode; }; JNIEXPORT void JNICALL Java_cc_ptt_java_IOSpeed_arraycopyImpl(JNIEnv *env, jclass klass, jbyteArray srcArray, jint srcOffset, jintArray destArray, jint destOffset, jint numsInt) { PrimitiveArray source(env, srcArray, JNI_ABORT); PrimitiveArray dest(env, destArray, 0); u_long *srcP = reinterpret_cast<u_long *>( source + srcOffset * sizeof (jbyte)); u_long *end = srcP + numsInt; u_long *destP = reinterpret_cast<u_long *>( dest + destOffset * sizeof(jint)); while (srcP < end) *destP++ = ntohl(*srcP++); } 看到这里 NIO 能带来多大的助益,各位心里各自有一把尺,我自己则是对我 之前推文里的看法「NIO 带来效率数十倍的提升」持怀疑的心态。 --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 218.164.110.25 ※ 编辑: sbrhsieh 来自: 218.164.110.25 (10/06 01:05)
1F:→ realmeat:我也开始怀疑了 10/06 07:26
2F:→ bitlife:我当初看到nio第一个感觉是移植C的指标+索引以直接存取缓 10/06 09:15
3F:→ bitlife:冲区会比较方便有效率,当然还有其它的特异功能 10/06 09:28







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:WOW站内搜寻

TOP