Я пытаюсь сделать локальный IPC с помощью Сокетов и Объектных потоков в Java однако, я вижу низкую производительность.
Я тестирую время ping отправки объекта через ObjectOutputStream к получению ответа через ObjectInputStream по Сокету.
Вот проситель:
public SocketTest(){
int iterations = 100;
try {
Socket socket = new Socket("localhost", 1212);
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
double start = System.currentTimeMillis();
for (int i = 0; i < iterations; ++i) {
Request request = new Request();
objectOutputStream.writeObject(request);
Response response = (Response)objectInputStream.readObject();
}
double finish = System.currentTimeMillis();
System.out.println("Per ping: " + (finish - start) / iterations );
} catch (Exception e) {
e.printStackTrace();
}
}
Вот респондент:
public ServerSocketTest(){
try {
ServerSocket serverSocket = new ServerSocket(1212);
Socket socket = serverSocket.accept();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Request request = (Request)objectInputStream.readObject();
while (request != null) {
Response response = new Response();
objectOutputStream.writeObject(response);
request = (Request)objectInputStream.readObject();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Результат, который я получаю:
На ping: 80.35
80 мс далеки для замедления для локального трафика.
Запрос и классы Ответа являются очень маленькими, и их сериализация быстра.
Я попытался наивно добавить:
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
с небольшим эффектом.
выполнение ping localhost:
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=64 time=0.035 ms
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=3 ttl=64 time=0.039 ms
64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=4 ttl=64 time=0.056 ms
также быстро.
Версия 1.6.0_05l Java, Работающая на RedHat 2.4
Вы пробовали встраивать запросы и ответы в BufferedInputStream / BufferedOutputStream ? Это должно значительно улучшить выступления.
Я ожидаю, что вам придется вызвать objectOutputStream.flush()
с обеих сторон, чтобы гарантировать, что данные будут немедленно отправлены в сеть. В противном случае стек TCP может ждать некоторое время для получения дополнительных данных, чтобы заполнить неполный IP-пакет.
Помимо использования буферизованных потоков и вызова flush () перед каждым чтением, вы также должны сначала создать ObjectOutputStream на обоих концах. Кроме того, тестирование для readObject (), возвращающего null, бессмысленно, если вы не планируете вызывать writeObject (null). Тест для EOS с readObject () - это catch (EOFException exc).
Итак, создайте BufferedOutputStream и очистите его перед созданием BufferedInputStream. Чтобы избежать зависания.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4788782
говорится, что в соответствии с документацией
Если вы измените тестовый пример таким образом, что как сервер AServer, так и AClient создает ObjectOutputStream перед ObjectInputStream, тест не блокирует . Это ожидаемое поведение с учетом следующей документации :
Конструктор ObjectOutputStream:
Создает ObjectOutputStream, который записывает в указанный
OutputStream. Этот конструктор записывает заголовок потока сериализации в базовый поток; вызывающие могут немедленно очистить поток , чтобы гарантировать, что конструкторы для получения
ObjectInputStreams не будут блокироваться при чтении заголовка .Конструктор ObjectInputStream:
Создает ObjectInputStream, который читает из указанного
InputStream. Заголовок потока сериализации считывается из потока и проверяется. Этот конструктор будет блокировать до тех пор, пока соответствующий
ObjectOutputStream не запишет и не очистит заголовок.