Действительно ли имеет значение размер объектов, которые вы отправляете через сокет с потоками ввода / вывода объектов?

#java #sockets #objectoutputstream #objectinputstream

#java #сокеты #objectoutputstream #objectinputstream

Вопрос:

Более эффективно очищать OutputStream после каждого отдельного вызова ObjectOutputStream#writeObject вместо очистки потока после последовательности операций записи объекта? (Пример: записать объект и сбросить 4 раза или записать 4 раза, а затем сбросить только один раз?)

Как ObjectOutputStream работает внутри?

Ответ №1:

Лучше ли каким-то образом отправлять четыре Object[5] (сбрасывая каждый из них), чем Object[20] , например?

Это не лучше. На самом деле это, вероятно, хуже, с точки зрения производительности. Каждый из этих сбросов заставит стек TCP / IP на уровне операционной системы отправлять данные «прямо сейчас». Если вы просто выполняете один сброс в конце, вы должны сэкономить на системных вызовах и на сетевом трафике.

Если вы еще этого не сделали, вставка a BufferedOutputStream между Socket OutputStream и ObjectOutputStream будет иметь гораздо большее значение для производительности. Это позволяет сериализованным данным накапливаться в памяти перед записью в поток сокета. Это потенциально экономит много системных вызовов и может повысить производительность на порядки … в зависимости от фактических отправляемых объектов.

(Представление четырех Object[5] объектов больше, чем одного Object[20] объекта, и это приводит к снижению производительности в первом случае. Однако это самое большее незначительно по сравнению с проблемами очистки и буферизации.)

Как этот поток работает внутри?

Это слишком общий вопрос, чтобы отвечать на него разумно. Я предлагаю вам ознакомиться с сериализацией, начиная с документов на этой странице.

Ответ №2:

Нет, это не должно иметь значения, если только у вас нет оснований полагать, что сетевое соединение, скорее всего, отключится, и частичные данные полезны. В противном случае это просто звучит как способ сделать код более сложным без всякой причины.

Ответ №3:

Если вы посмотрите на единственный общедоступный конструктор ObjectOutputStream, вы заметите, что для его создания требуется базовый OutputStream .

Когда и как вы очищаете свой ObjectStream, полностью зависит от типа потока, который вы используете. (И, учитывая все это, имейте в виду, что не все расширения OutputStream гарантированно выполнят ваш запрос на flush — это полностью не зависит от реализации, как это прописано в «контракте» javadocs.)

Но, конечно, мы можем порассуждать об этом и даже вытащить код и посмотреть, что на самом деле сделано.

ЕСЛИ базовый поток вывода должен использовать службы операционной системы для устройств (таких как диск или сетевой интерфейс в случае сокетов), то поведение flush() полностью зависит от операционной системы. Например, вы можете захватить выходной поток сокета, а затем создать экземпляр ObjectOutputStream для записи сериализованных объектов в сеть. За реализацию TCP / IP отвечает ОС хоста.

Что более эффективно?

Что ж, если ваш объектный поток обертывает ByteArrayOutputStream, вы потенциально сталкиваетесь с серией перераспределений и вызовов System.arrayCopy(). Я говорю потенциально, поскольку реализация массива байтов удваивает размер каждой (внутренней) операции resize(), и очень маловероятно, что запись n (небольших) объектов и очистка каждый раз приведут к n перераспределениям. (Где предполагается, что n — достаточно небольшое число).

Но если вы обертываете сетевой поток, вы должны иметь в виду, что сетевая запись обходится очень дорого. Гораздо разумнее, если ваш протокол позволяет это, разделять ваши записи (для заполнения буфера отправки) и просто сбрасывать один раз.