Мне интересно, когда методы записи GatheringByteChannel (с массивом ByteBuffers) имеют преимущества по сравнению с "обычными" методами записи WritableByteChannel.
Я попытался выполнить тест, в котором я мог бы использовать метод обычного сопоставления и сбора записи в FileChannel, с общим объемом около 400 КБ / с в байтовых буферах длиной от 23 до 27 байтов в обоих случаях. При сборе записей использовался массив из 64. Обычный метод использовал примерно 12% моего ЦП, а метод сбора использовал около 16% моего ЦП (хуже, чем обычный метод!)
Это говорит о том, что НЕ полезно использовать сбор записей в FileChannel для этого диапазона рабочих параметров. Почему это так, и когда бы вы использовали GatheringByteChannel? (по сети ввода / вывода?)
Соответствующие различия здесь:
public void log(Queue<Packet> packets) throws IOException
{
if (this.gather)
{
int Nbuf = 64;
ByteBuffer[] bbufs = new ByteBuffer[Nbuf];
int i = 0;
Packet p;
while ((p = packets.poll()) != null)
{
bbufs[i++] = p.getBuffer();
if (i == Nbuf)
{
this.fc.write(bbufs);
i = 0;
}
}
if (i > 0)
{
this.fc.write(bbufs, 0, i);
}
}
else
{
Packet p;
while ((p = packets.poll()) != null)
{
this.fc.write(p.getBuffer());
}
}
}
Обновление:
Я провел некоторое тестирование, и подход к сбору для различных длин ByteBuffers, похоже, не принес пользы для файлового ввода-вывода. Гораздо более актуальной была «фрагментация» потока ввода-вывода по длине байтового буфера. Я изменил свою программу, чтобы она копировала относительно большой (27 МБ) файл, считывая входные данные в байтовые буферы определенной длины. Программа начинает значительно замедляться, если длина буферов составляет менее 256 байт.
Я решил попробовать третий вариант, а именно написать свою собственную простую процедуру "сбора", которая берет буферы и объединяет их в больший буфер перед записью в файловый канал. Это сметает метод GatheringByteChannel write(ByteBuffer[] buffers)
для скорости. (Примечание: размер чтение одинаков для всех трех режимов записи, поэтому тот факт, что я создаю кучу небольших байтовых буферов и использую их для чтения ввода-вывода, не вызывает существенного замедления Я немного разочарован тем, что Java не делает это за вас. Ну хорошо.
enum GatherType { NONE, AUTOMATIC, MANUAL }
static class BufferWriter
{
final private FileChannel fc;
private GatherType gather = GatherType.NONE;
BufferWriter(FileChannel f) { this.fc = f; }
public void setGather(GatherType gather) { this.gather=gather; }
public void write(Queue<ByteBuffer> buffers) throws IOException
{
switch (this.gather)
{
case AUTOMATIC:
{
int Nbuf = 64;
ByteBuffer[] bbufs = new ByteBuffer[Nbuf];
int i = 0;
ByteBuffer b;
while ((b = buffers.poll()) != null)
{
bbufs[i++] = b;
if (i == Nbuf)
{
this.fc.write(bbufs);
i = 0;
}
}
if (i > 0)
{
this.fc.write(bbufs, 0, i);
}
}
break;
case MANUAL:
{
ByteBuffer consolidatedBuffer = ByteBuffer.allocate(4096);
ByteBuffer b;
while ((b = buffers.poll()) != null)
{
if (b.remaining() > consolidatedBuffer.remaining())
{
consolidatedBuffer.flip();
this.fc.write(consolidatedBuffer);
consolidatedBuffer.clear();
}
if (b.remaining() > consolidatedBuffer.remaining())
{
this.fc.write(b);
}
else
{
consolidatedBuffer.put(b);
}
}
consolidatedBuffer.flip();
if (consolidatedBuffer.hasRemaining())
{
this.fc.write(consolidatedBuffer);
}
}
break;
case NONE:
{
ByteBuffer b;
while ((b = buffers.poll()) != null)
{
this.fc.write(b);
}
}
break;
}
}
}