简体   繁体   English

消息大小很大时,socketchannel.write()会变得非常慢

[英]socketchannel.write() becomes very slow when message size is large

In my program using java nio, the socketchannel.write() becomes very slow when it tries to write 10 KB messages consecutively. 在我使用java nio的程序中,当尝试连续写入10 KB消息时,socketchannel.write()变得非常慢。 The measured time for writing a complete 10 KB message is between 160 ms and 200 ms. 编写完整的10 KB消息的时间为160毫秒至200毫秒。 But the time for writing a complete 5 KB message is only takes 0.8 ms. 但是,编写完整的5 KB消息所需的时间仅为0.8 ms。

In the selector, I only have Selection.OP_READ and do not handle Selection.OP_WRITE. 在选择器中,我只有Selection.OP_READ,不处理Selection.OP_WRITE。 When a large complete message is received, it is written to another receiver 4 times. 接收到较大的完整消息时,会将其写入另一个接收者4次。

Is anyone accounter same problem? 有人会问同样的问题吗? There is a post about socketchannel.write() slow. 有一篇关于socketchannel.write()的文章。 My question is how to alternate change between OP_READ and OP_WRITE? 我的问题是如何在OP_READ和OP_WRITE之间交替更改?

If I add an inerval eg, 150 ms, the response time is reduced. 如果添加一个例如150 ms的间隔,则响应时间会缩短。 Is there any way to find when the buffer is full so I can let the program waits. 有什么办法可以找到缓冲区何时已满,以便让程序等待。 My operating system is windows xp. 我的操作系统是Windows XP。

Thanks. 谢谢。

I follow EPJ suggestion by checking the number of written bytes. 我通过检查写入的字节数来遵循EPJ的建议。 But the response time is still high. 但是响应时间仍然很高。 I post part of my code here and would like to examine whether there is wrong with my code. 我在这里发布了部分代码,并想检查我的代码是否有问题。

// this is the writeData() part using nio: //这是使用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);
    }

I suggest that your reading process is slow and that this is causing its receive buffer to back up, which is causing your send buffer to back up, which stalls your sends. 我建议您的读取过程很慢,这将导致其接收缓冲区备份,这将导致您的发送缓冲区备份,从而使发送停止。

Or else you haven't written the code correctly for non-blocking mode. 否则,您没有为非阻塞模式正确编写代码。 If you get a zero result from the write() method, you must (a) change the interestOps to OP_WRITE and (b) return to your select loop. 如果从write()方法得到的结果为零,则必须(a)将interestOps更改为OP_WRITE,并且(b)返回到select循环。 When you get OP_WRITE you must then repeat the write; 当您获得OP_WRITE时,您必须重复写入操作; if you wrote all the data, change the interestOps back to OP_READ, otherwise leave everything as is and wait for the next OP_WRITE. 如果您写入了所有数据,则将interestOps改回OP_READ,否则将所有内容保持不变,并等待下一个OP_WRITE。 If you attempt to loop while writing in non-blocking mode even in the presence of zero-length writes you will just spin, wasting CPU cycles and time. 如果您尝试在非阻塞模式下进行写操作时进行循环,即使存在零长度写操作,您也只会旋转,从而浪费了CPU周期和时间。

Modulo bugs: 模组错误:

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

If write takes more than 20 micro-seconds, I would suggest you have a buffer full issue. 如果写入时间超过20微秒,则建议您遇到缓冲区已满的问题。 I assume you are using blocking NIO. 我假设您正在使用阻止NIO。 When the send buffer is not full it usually takes between 5 - 20 micro-seconds. 当发送缓冲区未满时,通常需要5到20微秒。 In the past I have configured my server to kill any slow consumer which takes 2 ms to write. 过去,我已将服务器配置为杀死需要2毫秒写入时间的所有慢速消耗者。 (Possibly a bit aggressive. ;) (可能有点激进。)

You could try increasing the size of the send buffer (Socket.setSendBufferSize(int), which is also available for SocketChannels), but it would appear you are trying to send more data than your bandwidth allows. 您可以尝试增加发送缓冲区的大小(Socket.setSendBufferSize(int),该属性也可用于SocketChannels),但是看来您正在尝试发送的数据超出了带宽的允许范围。

10 KB is not a large message, the typical send buffer size is 64 KB, so for it to be full you would need to have 6-7 messages unsent. 10 KB不是一条大消息,典型的发送缓冲区大小是64 KB,因此要使其满,您将需要发送6-7条消息。 This might explain way 5KB is relatively fast. 这可以解释5KB的方式相对较快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM