当消息大小较大时,Socketchannel.write()变得非常慢



在我使用java nio的程序中,socketchannel.write()在尝试连续写入10 KB消息时变得非常慢。写入一个完整的10 KB消息的测量时间在160 ms到200 ms之间。但是写一条完整的5kb消息只需要0.8 ms。

在选择器中,我只有选择。OP_READ和不处理select . op_write。当接收到一个大的完整消息时,它被写入另一个接收者4次。

是否有人遇到同样的问题?有一篇关于socketchannel.write()慢的帖子。我的问题是如何在OP_READ和OP_WRITE之间交替变化?

如果我增加一个间隔,例如150毫秒,响应时间就会减少。有没有什么方法可以知道缓冲区什么时候满了,这样我就可以让程序等待。我的操作系统是windows xp。

谢谢。

我按照EPJ的建议检查写入的字节数。但是响应时间仍然很高。我把我的部分代码贴在这里,想检查一下我的代码是否有问题。

//这是使用nio的writeData()部分:

      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);
    }

我建议你的阅读过程很慢,这导致它的接收缓冲区备份,这导致你的发送缓冲区备份,这拖延你的发送。

或者您没有为非阻塞模式编写正确的代码。如果从write()方法得到零结果,则必须(a)将interestOps更改为OP_WRITE, (b)返回到选择循环。当你得到OP_WRITE时,你必须重复写;如果您写了所有数据,则将interestOps更改回OP_READ,否则保持所有内容不变并等待下一个OP_WRITE。如果在非阻塞模式下写操作时尝试循环,即使存在零长度的写操作,也会导致旋转,浪费CPU周期和时间。

模缺陷:

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);
}

如果写入时间超过20微秒,我建议您存在缓冲区已满的问题。我假设您正在使用阻塞NIO。当发送缓冲区未满时,通常需要5 - 20微秒。在过去,我已经将我的服务器配置为杀死任何写时间为2毫秒的慢用户。(可能有点咄咄逼人。;)

您可以尝试增加发送缓冲区的大小(Socket.setSendBufferSize(int),这也可用于SocketChannels),但看起来您正在尝试发送超过带宽允许的数据。

10 KB不是一个大的消息,典型的发送缓冲区大小是64 KB,因此要使其满,您需要有6-7个未发送的消息。这也许可以解释为什么5KB相对较快。

最新更新