在处理多个千兆字节文件时,我注意到了一些奇怪的事情:似乎使用文件通道从文件读取到分配有allocateDirect的重复使用的ByteBuffer对象中,比从MappedByteBuffer中读取要慢得多,实际上,它甚至比读取字节中的记录还要慢。使用常规读取调用的数组!
我期望它(几乎)与从mapedbytebuffers读取的速度一样快,因为我的ByteBuffer是使用allocateDirect分配的,因此读取应该直接结束于我的字节缓冲区,而没有任何中间副本。
我现在的问题是:我做错了什么?还是字节缓冲区+文件通道确实比常规的io / mmap慢?
在下面的示例代码中,我还添加了一些代码,可将读取的内容转换为长值,因为这是我的真实代码经常执行的操作。我希望ByteBuffer
getLong()方法比我自己的字节shuffeler快得多。
测试结果:mmap:3.828字节缓冲区:55.097常规I / O:38.175
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.MappedByteBuffer;
class testbb {
static final int size = 536870904, n = size / 24;
static public long byteArrayToLong(byte [] in, int offset) {
return ((((((((long)(in[offset + 0] & 0xff) << 8) | (long)(in[offset + 1] & 0xff)) << 8 | (long)(in[offset + 2] & 0xff)) << 8 | (long)(in[offset + 3] & 0xff)) << 8 | (long)(in[offset + 4] & 0xff)) << 8 | (long)(in[offset + 5] & 0xff)) << 8 | (long)(in[offset + 6] & 0xff)) << 8 | (long)(in[offset + 7] & 0xff);
}
public static void main(String [] args) throws IOException {
long start;
RandomAccessFile fileHandle;
FileChannel fileChannel;
// create file
fileHandle = new RandomAccessFile("file.dat", "rw");
byte [] buffer = new byte[24];
for(int index=0; index<n; index++)
fileHandle.write(buffer);
fileChannel = fileHandle.getChannel();
// mmap()
MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, size);
byte [] buffer1 = new byte[24];
start = System.currentTimeMillis();
for(int index=0; index<n; index++) {
mbb.position(index * 24);
mbb.get(buffer1, 0, 24);
long dummy1 = byteArrayToLong(buffer1, 0);
long dummy2 = byteArrayToLong(buffer1, 8);
long dummy3 = byteArrayToLong(buffer1, 16);
}
System.out.println("mmap: " + (System.currentTimeMillis() - start) / 1000.0);
// bytebuffer
ByteBuffer buffer2 = ByteBuffer.allocateDirect(24);
start = System.currentTimeMillis();
for(int index=0; index<n; index++) {
buffer2.rewind();
fileChannel.read(buffer2, index * 24);
buffer2.rewind(); // need to rewind it to be able to use it
long dummy1 = buffer2.getLong();
long dummy2 = buffer2.getLong();
long dummy3 = buffer2.getLong();
}
System.out.println("bytebuffer: " + (System.currentTimeMillis() - start) / 1000.0);
// regular i/o
byte [] buffer3 = new byte[24];
start = System.currentTimeMillis();
for(int index=0; index<n; index++) {
fileHandle.seek(index * 24);
fileHandle.read(buffer3);
long dummy1 = byteArrayToLong(buffer1, 0);
long dummy2 = byteArrayToLong(buffer1, 8);
long dummy3 = byteArrayToLong(buffer1, 16);
}
System.out.println("regular i/o: " + (System.currentTimeMillis() - start) / 1000.0);
}
}
由于装入大块然后进行处理不是一个选择(我将在各处读取数据),我认为我应该坚持使用MappedByteBuffer。谢谢大家的建议。
我相信你只是在做微优化,这 可能只是 无关紧要 (www.codinghorror.com)
。
下面是一个具有较大缓冲区并删除了多余seek
/ setPosition
调用的版本。
mmap: 1.358 bytebuffer: 0.922 regular i/o: 1.387
mmap: 1.336 bytebuffer: 1.62 regular i/o: 1.467
mmap: 3.262 bytebuffer: 106.676 regular i/o: 90.903
这是代码:
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.MappedByteBuffer;
class Testbb2 {
/** Buffer a whole lot of long values at the same time. */
static final int BUFFSIZE = 0x800 * 8; // 8192
static final int DATASIZE = 0x8000 * BUFFSIZE;
static public long byteArrayToLong(byte [] in, int offset) {
return ((((((((long)(in[offset + 0] & 0xff) << 8) | (long)(in[offset + 1] & 0xff)) << 8 | (long)(in[offset + 2] & 0xff)) << 8 | (long)(in[offset + 3] & 0xff)) << 8 | (long)(in[offset + 4] & 0xff)) << 8 | (long)(in[offset + 5] & 0xff)) << 8 | (long)(in[offset + 6] & 0xff)) << 8 | (long)(in[offset + 7] & 0xff);
}
public static void main(String [] args) throws IOException {
long start;
RandomAccessFile fileHandle;
FileChannel fileChannel;
// Sanity check - this way the convert-to-long loops don't need extra bookkeeping like BUFFSIZE / 8.
if ((DATASIZE % BUFFSIZE) > 0 || (DATASIZE % 8) > 0) {
throw new IllegalStateException("DATASIZE should be a multiple of 8 and BUFFSIZE!");
}
int pos;
int nDone;
// create file
File testFile = new File("file.dat");
fileHandle = new RandomAccessFile("file.dat", "rw");
if (testFile.exists() && testFile.length() >= DATASIZE) {
System.out.println("File exists");
} else {
testFile.delete();
System.out.println("Preparing file");
byte [] buffer = new byte[BUFFSIZE];
pos = 0;
nDone = 0;
while (pos < DATASIZE) {
fileHandle.write(buffer);
pos += buffer.length;
}
System.out.println("File prepared");
}
fileChannel = fileHandle.getChannel();
// mmap()
MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, DATASIZE);
byte [] buffer1 = new byte[BUFFSIZE];
mbb.position(0);
start = System.currentTimeMillis();
pos = 0;
while (pos < DATASIZE) {
mbb.get(buffer1, 0, BUFFSIZE);
// This assumes BUFFSIZE is a multiple of 8.
for (int i = 0; i < BUFFSIZE; i += 8) {
long dummy = byteArrayToLong(buffer1, i);
}
pos += BUFFSIZE;
}
System.out.println("mmap: " + (System.currentTimeMillis() - start) / 1000.0);
// bytebuffer
ByteBuffer buffer2 = ByteBuffer.allocateDirect(BUFFSIZE);
// buffer2.order(ByteOrder.nativeOrder());
buffer2.order();
fileChannel.position(0);
start = System.currentTimeMillis();
pos = 0;
nDone = 0;
while (pos < DATASIZE) {
buffer2.rewind();
fileChannel.read(buffer2);
buffer2.rewind(); // need to rewind it to be able to use it
// This assumes BUFFSIZE is a multiple of 8.
for (int i = 0; i < BUFFSIZE; i += 8) {
long dummy = buffer2.getLong();
}
pos += BUFFSIZE;
}
System.out.println("bytebuffer: " + (System.currentTimeMillis() - start) / 1000.0);
// regular i/o
fileHandle.seek(0);
byte [] buffer3 = new byte[BUFFSIZE];
start = System.currentTimeMillis();
pos = 0;
while (pos < DATASIZE && nDone != -1) {
nDone = 0;
while (nDone != -1 && nDone < BUFFSIZE) {
nDone = fileHandle.read(buffer3, nDone, BUFFSIZE - nDone);
}
// This assumes BUFFSIZE is a multiple of 8.
for (int i = 0; i < BUFFSIZE; i += 8) {
long dummy = byteArrayToLong(buffer3, i);
}
pos += nDone;
}
System.out.println("regular i/o: " + (System.currentTimeMillis() - start) / 1000.0);
}
}
问题内容: 我在Java2D方面表现有些古怪。我知道sun.java2d.opengl VM参数可以为2D启用3D加速,但是即使使用该参数也有一些奇怪的问题。 这是我运行的测试结果: 在JComponent上绘制具有32x32像素图块的25x18地图, 图像1 = .bmp格式,图像2 = .png格式 没有-Dsun.java2d.opengl = true 使用.BMP图像1的120 FPS使
最近,我们将数据库从11g更新为19c。 在新数据库版本中测试应用程序时,我们遇到了一个特定视图的性能问题,该视图工作得非常好,但在19c中会导致性能问题。 在分析计划时,我们看到执行计划发生了巨大变化,这导致了19c中视图的性能非常差。 令人惊讶的是,其他观点的效果很好。 如果你能对这个问题有所了解,那就太好了。 谢谢你,JD
我是Spark和Cassandra的新学员。我正面临着一个主要的性能问题,我在Spark中每5秒将来自Kafka的数据流化,然后使用JRI在R语言中对数据执行分析,最后将数据保存到Cassandra各自的列族中。将数据保存到Cassandra的持续时间(以毫秒为单位)随着输入请求的数量迅速增加[每个请求为200KB]。 火花代码:
问题内容: 我读到React非常快。最近,我写了一个应用程序来测试对角的反应。不幸的是,我发现反应的表现要慢于角度反应。 http://shojib.github.io/ngJS/#/speedtest/react/1 这是react的源代码。我是新来的人。我确定我的反应代码在这里做错了。我发现它异常缓慢。 https://jsbin.com/viviva/edit?js,输出 看看是否有任何反应
我有一个flink作业(scala),它基本上是从Kafka主题(1.0)读取数据,聚合数据(1分钟事件时间翻转窗口,使用折叠函数,我知道这是不推荐的,但比聚合函数更容易实现),并将结果写入两个不同的Kafka主题。 问题是——当我使用FS状态后端时,一切都运行顺利,检查点需要1-2秒,平均状态大小为200 mb——也就是说,直到状态大小增加(例如,在缩小差距的同时)。 我想我会尝试使用rocks
所以我在FXML中定义了一个ListView 以及相应的方法 方法不是很大,但是第一行代码只在5秒后执行!但是在同一程序中的另一个ListView中,ListView没有速度问题?怎么会呢?如果需要任何其他信息,请评论