socketchannel.write () становится очень медленным, когда размер сообщения велик - PullRequest
1 голос
/ 08 ноября 2011

В моей программе, использующей java nio, socketchannel.write () становится очень медленным, когда пытается последовательно написать сообщения размером 10 КБ.Измеренное время для записи полного сообщения 10 КБ составляет от 160 мс до 200 мс.Но время записи полного 5 КБ сообщения составляет всего 0,8 мс.

В селекторе у меня есть только Selection.OP_READ и я не обрабатываю Selection.OP_WRITE.Когда получено большое полное сообщение, оно записывается другому получателю 4 раза.

Есть ли у кого-нибудь такая же проблема?Там есть пост про socketchannel.write () медленный.У меня вопрос, как чередовать изменения между OP_READ и OP_WRITE?

Если добавить инервал, например, 150 мс, время отклика уменьшится.Есть ли способ узнать, когда буфер заполнен, чтобы я мог позволить программе ждать.Моя операционная система Windows XP.

Спасибо.

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

// это часть writeData () с использованием nio:

      while (buffer.hasRemaining()) {   
        try {           
                buffer.flip();                  
                n = socket.write(buffer);           
                if(n == 0) {                
                    key.interestOps(SelectionKey.OP_WRITE);
                    key.attach(buffer);             
                    break;
                }                               
        } catch (IOException e) {               
            e.printStackTrace();
        } finally {
            buffer.compact();
        }
    }   

    if(buffer.position()==0) {                  
        key.interestOps(SelectionKey.OP_READ);
    }

Ответы [ 2 ]

3 голосов
/ 08 ноября 2011

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

правильно написал код для неблокирующего режима.Если вы получите нулевой результат от метода write (), вы должны (а) изменить интереса на OP_WRITE и (б) вернуться к циклу выбора.Когда вы получаете OP_WRITE, вы должны затем повторить запись;если вы записали все данные, измените интереса обратно на OP_READ, в противном случае оставьте все как есть и дождитесь следующего OP_WRITE.Если вы попытаетесь выполнить цикл во время записи в неблокирующем режиме даже при наличии операций записи нулевой длины, вы просто будете вращаться, тратя время процессора и время.

Ошибки по модулю:

while (buffer.position() > 0)
{
  try
  {
    buffer.flip();
    int count = ch.write(buffer);
    if (count == 0)
    {
      key.interestOps(SelectionKey.OP_WRITE);
      break;
    }
  }
  finally
  {
    buffer.compact();
  }
}
if (buffer.position() == 0)
{
  key.interestOps(SelectionKey.OP_READ);
}
2 голосов
/ 08 ноября 2011

Если запись занимает более 20 микросекунд, я бы посоветовал вам заполнить буфер. Я предполагаю, что вы используете блокировку NIO. Когда буфер отправки не заполнен, это обычно занимает от 5 до 20 микросекунд. Раньше я настраивал свой сервер для уничтожения любого медленного потребителя, который записывал 2 мс. (Возможно, немного агрессивно.;)

Вы можете попробовать увеличить размер буфера отправки (Socket.setSendBufferSize (int), который также доступен для SocketChannels), но может показаться, что вы пытаетесь отправить больше данных, чем позволяет ваша пропускная способность.

10 КБ - это не большое сообщение, типичный размер буфера отправки составляет 64 КБ, поэтому для его заполнения вам потребуется 6-7 неотправленных сообщений. Это может объяснить, почему 5 КБ относительно быстр.

...