Java: преимущества GatheringByteChannel?

Мне интересно, когда GatheringByteChannel< Методы записи /a> (принимающие массив байтовых буферов) имеют преимущества перед «обычными» методами записи WritableByteChannel.

Я попробовал тест, в котором я мог использовать обычный метод записи по сравнению со сбором в FileChannel, с общим объемом около 400 КБ/сек в ByteBuffers длиной от 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;
        }
    }
}

person Jason S    schedule 21.05.2010    source источник
comment
Вы, вероятно, не хотите использовать более 16 буферов для чтения или записи. Я знаю, что у Java 5 было жесткое ограничение в 16 (принималось бы больше, но читалось/записывалось бы только 16 из них) из-за ограничения в Solaris.   -  person Michael Barker    schedule 22.05.2010


Ответы (1)


Создает ли packets.poll() каждый раз новый Buffer? Если нет, вы пишете неверные данные в первом случае.

person Ha.    schedule 22.05.2010