#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 — достаточно небольшое число).
Но если вы обертываете сетевой поток, вы должны иметь в виду, что сетевая запись обходится очень дорого. Гораздо разумнее, если ваш протокол позволяет это, разделять ваши записи (для заполнения буфера отправки) и просто сбрасывать один раз.